首页 > 解决方案 > 如何使用 Azure AD 对同一应用程序的多个实例进行身份验证

问题描述

我是 Azure Active Directory 身份验证的新手,我正在尝试弄清楚如何实现我们对 Azure Active Directory 身份验证的要求。

我们有同一个 Web 应用程序的多个实例。即每个客户端有一个虚拟目录和一个数据库。不应允许来自一个实例的用户访问应用程序的其他实例。我们是否可以使用包含所有用户的单个 Active Directory 和单个 Azure AD 应用程序来实现这一点,或者我们是否需要为每个客户端创建 Active Directory 和单独的 Azure AD 应用程序?限制将通过应用程序代码实现,但是有没有办法对用户进行分组,以便我们可以在身份验证响应中获得一些值来确定用户可以访问哪个实例?

标签: c#azureazure-active-directory

解决方案


1. 我们有同一个 Web 应用程序的多个实例。即每个客户端有一个虚拟目录和一个数据库。不应允许来自一个实例的用户访问应用程序的其他实例。我们可以使用包含所有用户的单个 Active Directory 来实现这一点吗?

是的,你可以这么做。您可以为 Azure SQL Server 中的每个数据库创建 Azure AD 组,并将 SQL 角色分配给该组。那么如果你想让一个用户访问一个数据库,你只需要将用户添加到组中。更多详细信息,请参阅文档 步骤如下

  1. 为 Azure SQL 服务器创建 Azure AD 管理员
Connect-AzAccount
Set-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName "Group-23" -ServerName "demo_server" -DisplayName "user name" -ObjectId "user object id"
  1. 为每个数据库创建 Azure AD 组

    一个。使用上面的 Azure AD 使用登录 SQL 服务器 vai SSMS b。创造

    CREATE USER [GroupNmae] FROM EXTERNAL PROVIDER
    ALTER ROLE db_owner ADD MEMBER [GroupNmae]
    
  2. 将用户添加到 AD 组
Connect-AzureAD
Add-AzureADGroupMember -ObjectId <group id> -RefObjectId <user id>

2.限制将通过应用程序代码实现,但是有没有办法对用户进行分组,以便我们可以在身份验证响应中获取一些值来识别用户可以访问哪个实例?

根据我的测试,我们可以使用 AzureAD 令牌角色声明来实现。我们可以通过为 AD 组分配应用角色来为 Azure SQL 服务器中的每个数据库创建应用角色。更多关于应用角色的信息,请参考文档

详细步骤如下。

  1. 创建 Azure AD 应用程序

  2. 配置应用权限 在此处输入图像描述

  3. 添加应用角色

    • 选择您要在其中定义应用程序角色的应用程序。然后选择Manifest

    • appRoles通过找到设置并添加所有应用程序角色来编辑应用程序清单

    例如

"appId": "8763f1c4-f988-489c-a51e-158e9ef97d6a",
"appRoles": [
 {
   "allowedMemberTypes": [
     "User"
   ],
   "displayName": "your databse name",
   "id": "<GUID>",
   "isEnabled": true,
   "description": "access database <your databse name>",
   "value": "your databse name"
 }
],
"availableToOtherTenants": false,
  1. 代码

    一个。创建 Stratup.cs

    public void ConfigureAuth(IAppBuilder app)
     {
    
         JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
         app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
    
         app.UseCookieAuthentication(new CookieAuthenticationOptions());
    
         app.UseOpenIdConnectAuthentication(
             new OpenIdConnectAuthenticationOptions
             {
                 Authority = authority,
                 ClientId = appId,
                 ClientSecret = appSecret,
                 RedirectUri = redirectUri,
                 PostLogoutRedirectUri = redirectUri,
                 Scope = "openid profile offline_access https://database.windows.net//.default",
                 ResponseType=OpenIdConnectResponseTypes.CodeIdToken,
                 TokenValidationParameters = new TokenValidationParameters
                 {
                     ValidateIssuer = false,
                     RoleClaimType = "roles"
    
    
    
                 },
                 Notifications = new OpenIdConnectAuthenticationNotifications()
                 {
                     AuthenticationFailed = OnAuthenticationFailed,
                     AuthorizationCodeReceived= OnAuthorizationCodeReceived
                 }
             }
         );
    
     }
    
     private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
     {
         var idClient = var idClient = ConfidentialClientApplicationBuilder.Create(appId)
                               .WithAuthority(authority)
                               .WithRedirectUri(redirectUri)
                               .WithClientSecret(appSecret)
                               .Build();
    
    
         string[] scopes = "openid profile offline_access https://database.windows.net//.default".Split(' ');
         AuthenticationResult result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();
    
     }
    
     private Task OnAuthenticationFailed(AuthenticationFailedNotification<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
     {
         notification.HandleResponse();
         notification.Response.Redirect("/Error?message=" + notification.Exception.Message);
         return Task.FromResult(0);
     }
    

    湾。获取角色值

     ClaimsPrincipal.Current.FindFirst("roles").Value;
    

关于如何实现这一点,您可以参考示例以获取更多详细信息。


推荐阅读