在 Azure Active Directory 中使用授权属性

Using the Authorize attribute with Azure Active Directory

我正在尝试在测试应用程序上使用 [Authorize(Roles="test")] and/or call User.IsInRole("test") 但它不适用于我。在 Azure 管理门户的应用程序配置中,我在应用程序清单中启用了 SecurityGroup 声明,还设置了委派权限以允许 "Read all groups" 和 "Read directory data"。执行此操作后,我能够在 (ClaimsPrincipal.Current.Identity as ClaimsIdentity).FindAll("groups") 中看到测试组的 SID,但授权属性和对 IsInRole 的调用不起作用。是否需要其他任何东西才能让它发挥作用?

Azure AD 不发送角色声明中的组,也不发送组的名称(在多租户系统中,这意义不大:"admin" 在 contoso 中可能具有完全不同的语义来自 fabrikam 中的 "admin")。 Azure AD 有一个代表实际角色的新构造,而不是组。如果您想根据 角色 的名称检查访问权限,请参阅 https://github.com/Azure-Samples/active-directory-dotnet-webapp-roleclaims/blob/master/WebApp-RoleClaims-DotNet 以获取使用应用程序角色的示例。 如果您想改为检查组的授权,则需要将组声明类型分配为 RoleClaimType(在 https://github.com/Azure-Samples/active-directory-dotnet-webapp-roleclaims/blob/master/WebApp-RoleClaims-DotNet/App_Start/Startup.Auth.cs 中,您可以看到它是如何为应用程序角色完成的)以便 ASP.NET 知道这是声明验证 Authorize 和 IsInRole 何时发挥作用。此外,假设您没有获得组名,则需要对组的 objectId 执行检查。如果你想使用组并检查组名,它会变得复杂。您需要调用图 API 将组的 ObjectId 转换为其名称,并相应地增加传入的声明集合。

在 ASP.NET 5 和 MVC 6 中,您需要做的就是正确配置。这是对我来说很有魅力的代码:

public void ConfigureApplication(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ...

        app.UseIISPlatformHandler();
        app.UseStaticFiles();

        app.UseCookieAuthentication(options =>
        {
            options.AutomaticAuthenticate = true;
        });            

        app.UseOpenIdConnectAuthentication(options =>
        {
            options.AutomaticChallenge = true;
            options.ClientId = Configuration.Get<string>("Authentication:AzureAd:ClientId");
            options.Authority = Configuration.Get<string>("Authentication:AzureAd:AADInstance") + "Common";
            options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = false,
                RoleClaimType = "roles"
            };
            options.Events = new OpenIdConnectEvents
            {
                OnAuthenticationValidated = (context) => Task.FromResult(0),
                OnAuthenticationFailed = (context) =>
                {
                    context.Response.Redirect("/Home/Error");
                    context.HandleResponse(); // Suppress the exception
                    return Task.FromResult(0);
                },
                OnRemoteError = (context) => Task.FromResult(0)
            };
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(name: "default", template: "{controller=Dashboard}/{action=Index}/{id?}");                
        });

        DatabaseInitializer.InitializaDatabaseAsync(app.ApplicationServices).Wait();
    }