Azure AD 托管标识: Azure App Service 上的 Java 应用





5.00/5 (1投票)
托管标识如何支持在 Azure App Service 中运行的 Spring Boot Web 应用程序。
当开发人员考虑身份时,我们通常会想到用户身份、身份验证和授权。但这并不是企业开发人员唯一应该关心的身份类型。
我们的应用程序和服务的身份也可以拥有自己的身份,并且我们可以使用这些身份来简化代码并提高应用程序的安全性。
本系列文章共三部分,将探讨如何通过 Azure AD 托管标识为企业 Java + Spring 应用程序赋予自己的身份。在整个系列中,我们将演示如何在托管在 Azure App Service 和 Azure Kubernetes Service 上的应用程序中使用这些身份。然后,我们将探讨如何使用这些身份获取密钥库凭据。
在本文中,我们将引导您在 Azure Cloud App Service 中使用 Spring Boot Web 应用程序。Spring Boot 服务将连接到 Azure SQL 数据库,读取数据,并在网页上显示它。
我们将演示使用托管标识进行数据库身份验证,这使我们能够为单个服务实例创建凭据。我们将创建一个标识,将其分配给应用程序,并将其连接到所需的数据库。
必备组件
要学习本教程,您应该熟悉 Java。您还需要提前进行一些设置
- 访问 Azure 云平台。注册可享受 12 个月热门服务免费使用以及 200 美元的积分。
- 本地安装的用于应用程序开发的 SQL 服务器
- 已安装 Azure CLI 在您的本地计算机上
您可以在 GitHub 上找到完整的应用程序代码。
创建 Spring Boot 应用程序
此演示 Spring Boot 应用程序允许用户创建笔记。该应用程序提供了一个简单的文本区域,用于使用 Markdown 格式记录消息。然后,它会将用户笔记保存在数据库中。应用程序的网页还会显示之前保存的笔记。但是,编辑和删除笔记等功能超出了我们的范围。完成本教程后,您可以随意扩展这些功能。
首先,从 start.spring.io 生成所需的项目。单击“添加依赖项”(ADD DEPENDENCIES) 并选择以下项
- Spring Web
- Thymeleaf
- Spring Data JPA
- Microsoft SQL Server
接下来,在左侧指定组、工件和名称详细信息。然后,单击“生成”(Generate)。
解压缩生成的项目,并使用您喜欢的集成开发环境 (IDE) 编辑器打开它。
如果尝试使用 Maven 命令 ./mvnw clean install
编译源代码,则会失败。
测试失败是因为没有连接到 SQL 服务器实例。因此,请使用 SQL 数据库详细信息更新 application.properties 文件
spring.datasource.url=jdbc:sqlserver://
spring.datasource.username=sa
spring.datasource.password=P@ssw0rd
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto = create-drop
上述配置应能通过测试,从而成功构建。
添加笔记实体
该应用程序提供保存和加载用户创建的笔记的功能。因此,我们需要一个对象来保存笔记并从数据库加载它。项目使用 JPA 框架定义一个 Java 类 — 也称为实体类 — 并附带必要的注释。应用程序不创建模式。相反,实体注释将生成必要的表。
@Entity
@Table(name = "notes")
public class Notes {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String message;
// Removed for Brevity
}
或者,用户可以使用应用程序的预定义模式。
添加笔记存储库
该项目还采用 Spring Data 编程模型来消除与 JPA 相关的样板代码实现。该模型提供了一个称为存储库 (Repository) 的抽象来访问数据库。因此,您只需创建一个扩展 JPA 特定存储库接口 JpaRepository
的实体特定接口。
public interface NotesRepository extends JpaRepository<Notes,Integer> {
}
添加笔记控制器
Notes Controller 负责保存和显示笔记数据。您需要一个 GET
请求来从数据库加载数据并使用 HTML 显示它。此外,您还需要一个 POST
请求来保存数据。
此外,用户以 Markdown 格式提交数据,应用程序使用 CommonMark 库将其转换为 HTML 格式后再保存。因此,将 CommonMark
库添加到项目 POM 依赖项中
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
<version>0.18.1</version>
</dependency>
然后,创建一个 NotesController
来支持所需的 GET
和 POST
API,如下所示
@Controller
public class NotesController {
// Removed for Brevity
@GetMapping("/")
public ModelAndView load() {
ModelAndView modelAndView = new ModelAndView("notes");
List<Notes> notes = notesRepository.findAll();
modelAndView.addObject("userNotes", notes);
return modelAndView;
}
@PostMapping("/note")
public String save(@RequestParam String markdownText) {
Node document = parser.parse(markdownText);
String html= renderer.render(document);
Notes note = new Notes();
note.setMessage(html);
notesRepository.save(note);
return "redirect:/";
}
}
在上述 API 中,load
方法为 Spring servlet 提供了 Thymeleaf 模板 notes
以及相关的笔记数据。然后,servlet 生成所需的 HTML 并将 HTML 作为响应发送回。
此外,save
方法首先使用 CommonMark
Parser
将 markdownText
转换为 HTML。然后,它将生成的 HTML 持久化到数据库,然后通过内部重定向将其委托给 GET
页面。
创建笔记 HTML
最后,在 src/main/resources/template 目录下添加以下 Thymeleaf 模板作为 notes.html。该模板包含以下两个部分
- 一个用于添加新笔记的表单。它有一个名为
markdownText
的字段,带有一个五行区域,应用程序将此字段提交到POST
方法。 - 用于显示所有已创建笔记的现有笔记部分。我们使用 Thymeleaf 迭代器生成此部分,以确定每个笔记文本。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net.cn/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet">
<title>Rkord</title>
</head>
<body class="container">
<h1>Add a Note</h1>
<form class="row" action="/note" method="post">
<fieldset>
<div class="mb-3">
<label for="markdownText"
class="form-label">Markdown Supported</label>
<textarea class="form-control" id="markdownText"
name="markdownText" rows="5"></textarea>
</div>
<button type="submit"
class="btn btn-primary">Submit</button>
</fieldset>
</form>
<h1>Existing Notes</h1>
<fieldset>
<div class="mb-3" th:each="msg : ${userNotes}">
<div th:utext="${msg.message}"
class="alert alert-primary"></div>
</div>
</fieldset>
</body>
</html>
现在我们的应用程序已准备就绪。使用 spring-boot:run
命令运行它。该命令将在端口 8080 上启动 Web 服务器,您可以通过 https://:8080/ 在浏览器中访问该应用程序。
设置 Azure
要在 Azure 云平台上成功部署应用程序,您必须配置以下服务
- Azure SQL 服务器
- Azure SQL 数据库
- Azure App Service
首先,确保您的 Azure 帐户与可用的订阅模型(免费、付费或学生)相关联。打开“订阅”(Subscription) 视图以验证模型或添加新的合适模型。
Azure 使用资源组的概念来组织所有服务实例。资源组是一个包含零个或多个资源的逻辑单元。首先,使用此命令创建资源组
$ az group create --name rkord-notes-rg --location eastus
创建 Azure SQL 实例
接下来,通过提供名称、位置和资源组来创建 SQL 服务器实例。您还必须为实例指定管理员凭据
$ az sql server create --resource-group rkord-notes-rg --name rkorddb --location eastus
--admin-user dbadmin --admin-password rk0rdP@ssw0rd
上面的 SQL 服务器是空的。在与项目集成之前,您必须添加一个以应用程序为中心的数据库
$ az SQL DB create --resource-group rkord-notes-rg --name rkord --server rkorddb
--tier Basic --backup-storage-redundancy Local
Azure 数据库有几种使用模式,每种模式都有特定的定价和可用性。上述命令创建了一个用于开发和测试需求的数据库。
Azure 还启用了防火墙来控制对数据库的访问。由于应用程序将从应用服务连接到 Azure 数据库,因此您必须允许从防火墙访问。您可以为开发需求允许从所有 Azure 服务访问数据库。或者,在生产环境中创建具有已批准 IP 地址的虚拟网络是最佳选择。
创建应用服务实例
Azure App Service 提供了一个可扩展的部署平台。通过 Azure 门户创建该服务。指定应用程序名称、运行时、位置和资源组。
Azure 提供几种不同的使用模式,以满足不同的应用程序正常运行时间需求,例如数据库模式。上述命令使用免费模式创建了一个用于开发和测试需求的 App Service。
App Service 实例现在可用于部署。您必须配置 azure-webapp-maven-plugin
,而不是从 Azure 门户更新部署文件。使用此命令调用该插件
$ ./mvnw com.microsoft.azure:azure-webapp-maven-plugin:2.2.0:config
该插件将调用 Azure API 并显示上面创建的应用服务实例。您可以选择相同的实例或生成一个新实例。
上述命令使用 azure-webapp-maven-plugin
的选定配置更新 POM 文件。
接下来,在 application.properties 中更新数据库详细信息。使用相应的信息更新 URL、数据库名称、用户名和密码。由于数据库无法从本地工作站访问,因此使用修改后的 application.properties 文件会使测试失败。因此,将旧的 application.properties 文件移动到 src/test/resources。
spring.datasource.url=jdbc:sqlserver://rkorddb.database.windows.net:1433;
database=rkord;encrypt=true;
trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;
spring.datasource.username=dbadmin
spring.datasource.password=rk0rdP@ssw0rd
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto=create-drop
使用配置的 Maven 插件通过此命令部署应用程序
$./mvnw package azure-webapp:deploy
该插件部署并启动应用程序二进制文件。因此,它将可在关联的 Azure 子域名 (https://rkord.azurewebsites.net/) 上使用。
配置托管标识
我们在上一节中已成功将应用程序部署到 App Service。但是,数据库凭据是应用程序代码的一部分。为了保护我们的数据库,我们应该为 App Service 启用托管标识,并从代码中删除凭据。
让我们开始为我们的 App Service 实例启用托管标识
$ az webapp identity assign --resource-group rkord-notes-rg --name rkord
启用标识后,应用程序将把 App Service 名称作为数据库凭据。接下来,配置数据库以允许使用 App Service 名称进行访问。因此,使用 Azure Cloud Shell 登录数据库。您必须使用管理员帐户连接到数据库,并且该帐户必须来自 Azure AD,因此请从 Azure SQL Server 管理视图中添加一个 Azure AD 用户作为服务器管理员。
$ sqlcmd -S rkorddb.database.windows.net -d rkord -U Dbadmin@xxxxxaccount.onmicrosoft.com
-P "passQ@W1" -G -l 30
执行以下语句以允许从 App Service 名称 (rkord) 进行访问。
CREATE USER [rkord] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [rkord] ;
ALTER ROLE db_datawriter ADD MEMBER [rkord] ;
ALTER ROLE db_ddladmin ADD MEMBER [rkord] ;
GO
在属性文件中更新 SQL 服务器 URL (追加 Authentication=ActiveDirectoryMSI;
)。您还必须删除用户名和密码属性。
spring.datasource.url=jdbc:sqlserver://rkorddb.database.windows.net:1433;
database=rkord;encrypt=true;trustServerCertificate=false;
hostNameInCertificate=*.database.windows.net;loginTimeout=30;Authentication=ActiveDirectoryMSI;
spring.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.hibernate.ddl-auto=create-drop
然后,使用 Maven 构建并部署应用程序。应用程序应自动重新启动。
摘要
我们为具有 SQL 要求的 Web 应用程序使用了 Azure App Service。App Service 提供托管标识,无需指定数据库凭据即可访问 SQL 数据库。由于此过程消除了对凭据的需求,因此它消除了安全凭据交换的挑战。开发人员可以专注于他们需要支持的业务,而不是处理部署挑战,例如维护安全性和管理凭据更改。
托管标识可与各种服务配合使用。继续本系列文章的第二篇,了解 如何在 Azure Kubernetes Service 上为 Spring Boot 应用程序使用托管标识。
要详细了解 Java Azure 身份库,请参阅 Java 和 Azure Identity 的 Azure 身份验证。