首页 > c# > Dotnet Core 2.2 - Azure AD Auth Work但角色基础返回拒绝访问

Dotnet Core 2.2 - Azure AD Auth Work但角色基础返回拒绝访问 (Dotnet Core 2.2 - Azure AD Auth Work but Roles Base Returns Access Denied)

问题

我正在努力让角色在.Net Core 2.2中工作,其他解决方案都没有奏效。

在这个Startup.cs,微软在一个新的.Net 2.2中生成这个代码,由于某种原因不起作用,但是让这个块工作不是主题,尽管知道它为什么不是很好。说“没有指定authenticationScheme,并且没有找到DefaultChallengeScheme。” 但这正是微软所产生的。

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
                .AddAzureAd(options => Configuration.Bind("AzureAd", options));

在我的真实中,Startup.cs我必须使用下面的内容

services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddAzureAd(options => Configuration.Bind("AzureAd", options))
            .AddCookie();

所以上面是我使用Azure AD来处理该[Authorize]属性的唯一方法。问题在于,当我尝试使用角色进行授权时。我已经尝试过很多建议,但没有取得任何成功。每当我有一个[Authorize(Roles="")]我被重定向到Microsoft为Azure AD生成的AccessDenied()方法时AccountController,基本上是拒绝访问。我正在使用我在AD中创建的角色,也在Azure AD中创建了一个组,也使用了一个名为“域用户”的角色,该角色基本上是给公司中的每个员工,并且是每个员工拥有的最基本的授权。 。如果“域用户”获得“访问被拒绝”,那么我不知道我在这里不理解什么。

我已经关注了Microsoft文档的角色,但没有任何内容表明我需要为services.AddAuthentication()选项添加更多内容。

解决方法

以下是使用角色的.Net Core 2.2 Web App的功能。

编辑应用程序清单包括角色,例如

"appRoles": [
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Admins have the power.",
            "displayName": "Admin",
            "id": "282fc418-cf3a-4a3a-89f8-6500c64695ff",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Admin"
        },
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Writers have the ability to edit app data.",
            "displayName": "Writer",
            "id": "3aa1a322-2918-4005-8cc3-51cba010ccc0",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Writer"
        },
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Readers have the ability to read app data.",
            "displayName": "Reader",
            "id": "239f93af-4cc0-4d0e-ad04-bda1f8ac2a91",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Reader"
        }
    ]

Startup.cs

services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddAzureAd(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

services.AddHttpContextAccessor();

在代码的“顶部块”中添加扩展以解决您提到的问题。

AzureAdAuthenticationBuilderExtensions.cs

public static class AzureAdAuthenticationBuilderExtensions
{
    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
        => builder.AddAzureAd(_ => { });

    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
    {
        builder.Services.Configure(configureOptions);
        builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
        builder.AddOpenIdConnect();
        return builder;
    }

    private class ConfigureAzureOptions : IConfigureNamedOptions<OpenIdConnectOptions>
    {
        private readonly AzureAdOptions _azureOptions;

        public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
        {
            _azureOptions = azureOptions.Value;
        }

        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ResponseType = "token id_token";
            options.Resource = _azureOptions.TargetApiAppId;
            options.SaveTokens = true;
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;
        }

        public void Configure(OpenIdConnectOptions options)
        {
            Configure(Options.DefaultName, options);
        }
    }
}

AzureADOptions.cs

public class AzureAdOptions
{
    public string ClientId { get; set; }
    public string ClientSecret { get; set; }
    public string Instance { get; set; }
    public string Domain { get; set; }
    public string TenantId { get; set; }
    public string CallbackPath { get; set; }

    //manually added
    public string TargetApiAppId { get; set; }
}

在Enterprise应用程序刀片中为用户分配角色:

在此输入图像描述

装饰你的控制器:

[Authorize(Roles = "Writer")]

AccountController.cs

public class AccountController : Controller
{
    [HttpGet]
    public IActionResult SignIn()
    {
        var redirectUrl = Url.Action(nameof(HomeController.Index), "Home");
        return Challenge(
            new AuthenticationProperties { RedirectUri = redirectUrl },
            OpenIdConnectDefaults.AuthenticationScheme);
    }

    [HttpGet]
    public IActionResult SignOut()
    {
        var callbackUrl = Url.Action(nameof(SignedOut), "Account", values: null, protocol: Request.Scheme);
        return SignOut(
            new AuthenticationProperties { RedirectUri = callbackUrl },
            CookieAuthenticationDefaults.AuthenticationScheme,
            OpenIdConnectDefaults.AuthenticationScheme);
    }

    [HttpGet]
    public IActionResult SignedOut()
    {
        if (User.Identity.IsAuthenticated)
        {
            // Redirect to home page if the user is authenticated.
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

        return View();
    }

    [HttpGet]
    public IActionResult AccessDenied()
    {
        return View();
    }
}

问题

I'm trying to get roles working in .Net Core 2.2 and none of the other solutions have worked.

In the Startup.cs, Microsoft generates this code in a new .Net 2.2 which doesn't work for some reason but getting this block to work isn't the topic though it would be nice to know why it doesn't. Says "No authenticationScheme was specified, and there was no DefaultChallengeScheme found." But it is what Microsoft generated.

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
                .AddAzureAd(options => Configuration.Bind("AzureAd", options));

In my real Startup.cs I've had to use what's below

services.AddAuthentication(sharedOptions =>
            {
                sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddAzureAd(options => Configuration.Bind("AzureAd", options))
            .AddCookie();

So the above is the only way I've gotten Azure AD to work with the [Authorize] attribute. The issue is that when I try to authorize with roles. I've tried many of the suggestions but haven't had any success. Anytime I have an [Authorize(Roles="")] I get redirected to the AccessDenied() method in the AccountController that Microsoft generated for Azure AD, basically Access Denied. I'm using roles that I've made in AD, also made a group in Azure AD, also using a role called "Domain Users" which is basically given to every employee in the company and is the most basic authorization that every employee has. If "Domain Users" gets "access denied" then I have no idea what I'm not understanding here.

I've followed Microsoft docs for roles but there's nothing there that says I need to add more to the services.AddAuthentication() options.

解决方法

Here's what's working for me, .Net Core 2.2 Web App using Roles.

Edited application Manifest to include roles, E.g.

"appRoles": [
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Admins have the power.",
            "displayName": "Admin",
            "id": "282fc418-cf3a-4a3a-89f8-6500c64695ff",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Admin"
        },
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Writers have the ability to edit app data.",
            "displayName": "Writer",
            "id": "3aa1a322-2918-4005-8cc3-51cba010ccc0",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Writer"
        },
        {
            "allowedMemberTypes": [
                "User"
            ],
            "description": "Readers have the ability to read app data.",
            "displayName": "Reader",
            "id": "239f93af-4cc0-4d0e-ad04-bda1f8ac2a91",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "Reader"
        }
    ]

Startup.cs

services.AddAuthentication(sharedOptions =>
    {
        sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
    .AddAzureAd(options => Configuration.Bind("AzureAd", options))
    .AddCookie();

services.AddHttpContextAccessor();

Add extensions to workaround the issue you mentioned, in your "top block" of code.

AzureAdAuthenticationBuilderExtensions.cs

public static class AzureAdAuthenticationBuilderExtensions
{
    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder)
        => builder.AddAzureAd(_ => { });

    public static AuthenticationBuilder AddAzureAd(this AuthenticationBuilder builder, Action<AzureAdOptions> configureOptions)
    {
        builder.Services.Configure(configureOptions);
        builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, ConfigureAzureOptions>();
        builder.AddOpenIdConnect();
        return builder;
    }

    private class ConfigureAzureOptions : IConfigureNamedOptions<OpenIdConnectOptions>
    {
        private readonly AzureAdOptions _azureOptions;

        public ConfigureAzureOptions(IOptions<AzureAdOptions> azureOptions)
        {
            _azureOptions = azureOptions.Value;
        }

        public void Configure(string name, OpenIdConnectOptions options)
        {
            options.ResponseType = "token id_token";
            options.Resource = _azureOptions.TargetApiAppId;
            options.SaveTokens = true;
            options.ClientId = _azureOptions.ClientId;
            options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}";
            options.UseTokenLifetime = true;
            options.CallbackPath = _azureOptions.CallbackPath;
            options.RequireHttpsMetadata = false;
        }

        public void Configure(OpenIdConnectOptions options)
        {
            Configure(Options.DefaultName, options);
        }
    }
}

AzureADOptions.cs

public class AzureAdOptions
{
    public string ClientId { get; set; }
    public string ClientSecret { get; set; }
    public string Instance { get; set; }
    public string Domain { get; set; }
    public string TenantId { get; set; }
    public string CallbackPath { get; set; }

    //manually added
    public string TargetApiAppId { get; set; }
}

Assign role to the user in Enterprise applications blade:

enter image description here

Decorate your controller:

[Authorize(Roles = "Writer")]

AccountController.cs

public class AccountController : Controller
{
    [HttpGet]
    public IActionResult SignIn()
    {
        var redirectUrl = Url.Action(nameof(HomeController.Index), "Home");
        return Challenge(
            new AuthenticationProperties { RedirectUri = redirectUrl },
            OpenIdConnectDefaults.AuthenticationScheme);
    }

    [HttpGet]
    public IActionResult SignOut()
    {
        var callbackUrl = Url.Action(nameof(SignedOut), "Account", values: null, protocol: Request.Scheme);
        return SignOut(
            new AuthenticationProperties { RedirectUri = callbackUrl },
            CookieAuthenticationDefaults.AuthenticationScheme,
            OpenIdConnectDefaults.AuthenticationScheme);
    }

    [HttpGet]
    public IActionResult SignedOut()
    {
        if (User.Identity.IsAuthenticated)
        {
            // Redirect to home page if the user is authenticated.
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

        return View();
    }

    [HttpGet]
    public IActionResult AccessDenied()
    {
        return View();
    }
}
相似信息