簡體   English   中英

在ASP.NET核心中的每個操作之前查詢角色授權數據庫

[英]Query Database for Role Authorization Before Each Action in ASP.NET Core

結合Identity的ASP.NET Core已經提供了一種在登錄后檢查角色的簡單方法,但我想在每個控制器操作之前向數據庫查詢當前用戶的當前角色。

我已經閱讀了Microsoft的基於角色,基於策略和聲明的授權。 https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction )這些解決方案似乎都沒有檢查每個操作的角色。 以下是我最近嘗試以某種基於策略的授權的形式實現預期結果:

在Startup.cs中:

DatabaseContext context = new DatabaseContext();

services.AddAuthorization(options =>
{
    options.AddPolicy("IsManager",
        policy => policy.Requirements.Add(new IsManagerRequirement(context)));
    options.AddPolicy("IsAdmin",
        policy => policy.Requirements.Add(new IsAdminRequirement(context)));
});

在我的需求文件中:

public class IsAdminRequirement : IAuthorizationRequirement
{
    public IsAdminRequirement(DatabaseContext context)
    {
        _context = context;
    }

    public DatabaseContext _context { get; set; }
}
public class IsAdminHandler : AuthorizationHandler<IsAdminRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsAdminRequirement requirement)
    {
        // Enumerate all current users roles
        int userId = Int32.Parse(context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value);
        Roles adminRoles = requirement._context.Roles.FirstOrDefault(r => r.Name == "Administrator" && r.IsActive == true);
        bool hasRole = requirement._context.UserRoles.Any(ur => ur.UserId == userId && adminRoles.Id == ur.RoleId && ur.IsActive == true);
        // Check for the correct role
        if (hasRole)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

並在控制器中:

[HttpGet]
[Authorize(Policy = "IsAdmin")]
public async Task<IActionResult> Location()
{
    // do action here
}

使用此代碼,需求中間件以某種方式永遠不會被調用,因此永遠不會檢查數據庫。

在執行每個控制器操作之前,如何正確查詢數據庫以檢查當前用戶的角色?

我通過處理OnTokenValidated事件在我的應用程序(SignalR + JwtBearer)中解決了這個問題。 我只是檢查聲明中的角色與我的數據庫中的角色。 如果它們不再有效,我將TokenValidatedContext設置為失敗。

這是我的ASP.NET核心Startup.cs的摘錄:

services.AddAuthentication(x =>
{
    x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
    x.Events = new JwtBearerEvents
    {
        OnTokenValidated = async context =>
        {
            var userService = context.HttpContext.RequestServices.GetRequiredService<IUserRoleStore<User>>();
            var username = context.Principal.Identity.Name;
            var user = await userService.FindByNameAsync(username, CancellationToken.None);
            if (user == null)
            {
                // return unauthorized if user no longer exists
                context.Fail("Unauthorized");
            }
            else
            {
                // Check if the roles are still valid.
                var roles = await userService.GetRolesAsync(user, CancellationToken.None);
                foreach (var roleClaim in context.Principal.Claims.Where(p => p.Type == ClaimTypes.Role))
                {
                    if (roles.All(p => p != roleClaim.Value))
                    {
                        context.Fail("Unauthorized");
                        return;
                    }
                }
                context.Success();
            }
        },
        OnMessageReceived = context =>
        {
            var accessToken = context.Request.Query["access_token"];

            // If the request is for our hub...
            var path = context.HttpContext.Request.Path;
            if (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hubs"))
            {
                // Read the token out of the query string
                context.Token = accessToken;
            }
            return Task.CompletedTask;
        }
    };
    x.RequireHttpsMetadata = false;
    x.SaveToken = true;
    x.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidateIssuer = false,
        ValidateAudience = false
    };
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM