C# 在ASP.NET Core中的每个操作之前查询数据库中的角色授权
ASP.NET Core与Identity相结合已经提供了一种在登录后检查角色的简单方法,但是我想在每次控制器操作之前查询数据库中当前用户的当前角色 我已经阅读了Microsoft提供的基于角色、基于策略和基于声明的授权。() 这些解决方案似乎都无法检查每个操作的角色。以下是我最新的尝试,以基于策略的授权的形式实现所需的结果: 在Startup.cs中: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
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。这就是我最后所做的。这是一个很好的发现,但真正的问题仍然是一样的。让令牌验证和授权检查是不同的事情。