C# 在ASP.NET Core中的每个操作之前查询数据库中的角色授权

C# 在ASP.NET Core中的每个操作之前查询数据库中的角色授权,c#,authentication,asp.net-core,asp.net-core-mvc,user-roles,C#,Authentication,Asp.net Core,Asp.net Core Mvc,User Roles,ASP.NET Core与Identity相结合已经提供了一种在登录后检查角色的简单方法,但是我想在每次控制器操作之前查询数据库中当前用户的当前角色 我已经阅读了Microsoft提供的基于角色、基于策略和基于声明的授权。() 这些解决方案似乎都无法检查每个操作的角色。以下是我最新的尝试,以基于策略的授权的形式实现所需的结果: 在Startup.cs中: DatabaseContext context = new DatabaseContext(); services.AddAuthoriza

ASP.NET Core与Identity相结合已经提供了一种在登录后检查角色的简单方法,但是我想在每次控制器操作之前查询数据库中当前用户的当前角色

我已经阅读了Microsoft提供的基于角色、基于策略和基于声明的授权。() 这些解决方案似乎都无法检查每个操作的角色。以下是我最新的尝试,以基于策略的授权的形式实现所需的结果:

在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)));
});
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
    };
});
在我的需求文件中:

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;
    }
}
公共类IsAdminRequirement:IAAuthorizationRequirement
{
公共ISAdminRequest(数据库上下文)
{
_上下文=上下文;
}
公共数据库上下文_上下文{get;set;}
}
公共类IsAdminHandler:AuthorizationHandler
{
受保护的覆盖任务HandleRequirementAsync(授权HandlerContext上下文,ISAdminRequest要求)
{
//枚举所有当前用户角色
int userId=Int32.Parse(context.User.Claims.FirstOrDefault(c=>c.Type==ClaimTypes.NameIdentifier.Value);
Roles adminRoles=requirement.\u context.Roles.FirstOrDefault(r=>r.Name==“管理员”&&r.IsActive==true);
bool hasRole=requirement.\u context.UserRoles.Any(ur=>ur.UserId==UserId&&adminRoles.Id==ur.RoleId&&ur.IsActive==true);
//检查角色是否正确
如果(角色)
{
成功(要求);
}
返回Task.CompletedTask;
}
}
在控制器中:

[HttpGet]
[Authorize(Policy = "IsAdmin")]
public async Task<IActionResult> Location()
{
    // do action here
}
[HttpGet]
[授权(Policy=“IsAdmin”)]
公共异步任务位置()
{
//在这里行动
}
有了这段代码,就不会调用需求中间件,因此也不会检查数据库


在执行每个控制器操作之前,如何正确查询数据库以检查当前用户的角色?

我通过处理OnTokenValidated事件在应用程序(SignalR+JWTBear)中解决了这个问题。我只是检查声明中的角色与数据库中的角色。如果它们不再有效,我将TokenValidatedContext设置为failed

以下是我的ASP.NET Core 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)));
});
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
    };
});
services.AddAuthentication(x=>
{
x、 DefaultAuthenticateScheme=JwtBearerDefaults.AuthenticationScheme;
x、 DefaultChallengeScheme=JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x=>
{
x、 事件=新JWTBeareEvents
{
OnTokenValidated=异步上下文=>
{
var userService=context.HttpContext.RequestServices.GetRequiredService();
var username=context.Principal.Identity.Name;
var user=await userService.FindByNameAsync(用户名,CancellationToken.None);
if(user==null)
{
//如果用户不再存在,则返回unauthorized
上下文。失败(“未经授权”);
}
其他的
{
//检查角色是否仍然有效。
var roles=await userService.GetRolesAsync(用户,CancellationToken.None);
foreach(context.Principal.Claims.Where中的var roleClaim(p=>p.Type==ClaimTypes.Role))
{
if(roles.All(p=>p!=roleClaim.Value))
{
上下文。失败(“未经授权”);
返回;
}
}
context.Success();
}
},
OnMessageReceived=上下文=>
{
var accessToken=context.Request.Query[“访问令牌”];
//如果请求是针对我们的中心。。。
var path=context.HttpContext.Request.path;
if(!string.IsNullOrEmpty(accessToken)和&path.StartsWithSegments(“/hubs”))
{
//从查询字符串中读取令牌
context.Token=accessToken;
}
返回Task.CompletedTask;
}
};
x、 RequireHttpsMetadata=false;
x、 SaveToken=true;
x、 TokenValidationParameters=新的TokenValidationParameters
{
ValidateSuersigningKey=true,
IssuerSigningKey=新对称性安全密钥(密钥),
validateisuer=false,
ValidateAudience=false
};
});

您的实际问题是什么?为什么没有关于此的内容,或者如何正确执行此操作,或者其他内容?编辑以使问题更清楚。这不是对您的问题的回答,但可能值得一读:关于每个操作中的角色检查。您可以尝试覆盖控制器继承的OnActionExecuting操作并进行身份验证。谢谢,Patrick。这就是我最后所做的。这是一个很好的发现,但真正的问题仍然是一样的。让令牌验证和授权检查是不同的事情。