具有 Azure Entra ID 身份验证的 MVC

问题描述 投票:0回答:1

我刚刚创建了一个新的 MVC 项目并在 Azure 中创建了一个应用程序注册。以下是我目前拥有的代码:

启动.cs

public class Startup
{
    public IConfiguration Configuration { get; }
    public IWebHostEnvironment Env { get; set; }

    public Startup(IConfiguration configuration, IWebHostEnvironment env) {
        Configuration = configuration;
        Env = env;
    }

    public void ConfigureServices(IServiceCollection services) {
        services.AddDbContext<DataContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("Database")), ServiceLifetime.Singleton);

        services.AddHttpContextAccessor();

        services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));

        services.AddAuthorization(options => {
            options.AddPolicy("AzureAccount", policyBuilder => {
                policyBuilder.RequireAuthenticatedUser();
                policyBuilder.AddRequirements(new PolicyRequirement());
            });
        });

        services.AddSingleton<IAuthorizationHandler, PolicyAuthorizationHandler>();

        services.AddControllersWithViews();

        var mvcBuilder = services.AddControllersWithViews();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
        var cultureInfo = new CultureInfo("nl-NL");

        CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
        CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;

        if ( env.IsDevelopment() ) {
            app.UseDeveloperExceptionPage();
        } else {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints => {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

程序.cs

public class Program
{
    public static void Main(string[] args) {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder => {
                webBuilder.UseStartup<Startup>();
            });
}

PolicyAuthorizationHandler.cs

public class PolicyAuthorizationHandler : AuthorizationHandler<PolicyRequirement>
{
    private readonly DataContext _dataContext;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public PolicyAuthorizationHandler(DataContext dataContext, IHttpContextAccessor httpContextAccessor) {
        _dataContext = dataContext;
        _httpContextAccessor = httpContextAccessor;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authorizationHandlerContext, PolicyRequirement policyRequirement) {
        if ( await policyRequirement.Pass(_httpContextAccessor, _dataContext) ) {
            authorizationHandlerContext.Succeed(policyRequirement);
        }
    }
}

政策要求.cs

public class PolicyRequirement : IAuthorizationRequirement
{
    public async Task<bool> Pass(IHttpContextAccessor httpContextAccessor, DataContext dataContext) {
        bool authorized = false;

        if ( dataContext is not null ) {
            string? email = httpContextAccessor.HttpContext!.User.Identity?.Name;

            if ( email is not null ) {
                User? user = dataContext.Users.AsQueryable().Where(x => x.Email == email && x.Active).FirstOrDefault();

                if ( user is not null ) {

                    ClaimsIdentity claimsIdentity = new();
                    claimsIdentity.AddClaim(new(ClaimTypes.Email, email));
                    claimsIdentity.AddClaim(new(ClaimTypes.Name, user.Name));
                    claimsIdentity.AddClaim(new(ClaimTypes.Role, user.Role));

                    httpContextAccessor.HttpContext!.User.AddIdentity(claimsIdentity);

                    authorized = true;
                }
            }
        }

        return await Task.FromResult(authorized);
    }
}

我的 HomeController 具有

[Authorize("AzureAccount")]
属性,并且该控制器的 Index 方法具有
var identities = _httpContextAccessor.HttpContext.User.Identities
行。我在这条线上放置了一个断点,发现此时它将有 2 个身份。
PolicyRequirement.Pass
方法运行了两次,我不明白为什么。我该如何解决这个问题并确保
_httpContextAccessor.HttpContext.User.Identity
具有我自己设置的正确身份?预先感谢。

c# authentication asp.net-core-mvc authorization azure-app-registration
1个回答
0
投票

Microsoft Identity Web (MIW) 将自动处理将用户添加到身份变量中的操作。因此,如果您想采用经过身份验证的上下文以及 MIW 预先添加的身份,并将其替换为您自己的身份,则需要删除其中一个身份。

通过不删除 MIW 添加的原始用户身份,正如您所指出的,您将拥有两个身份,并且该函数将为每个身份运行。

在我看来,您为

PolicyRequirement
提供的代码似乎没有明显的需要。当您已经拥有 MIW 中间件提供的用户身份时,您的意图可能是导致您拥有一个兔子洞。
我还假设每次您使用
[Authorize("AzureAccount")]
属性到达端点时,您都会获得一个额外的身份(2,然后 3,然后 4,等等...)。

© www.soinside.com 2019 - 2024. All rights reserved.