我偶然发现了有关新的Asp.Net Core授权策略的讨论文章。许多人批评该功能,但是当我在Web API中处理授权问题时,我发现它对我很有用。
我的Web应用有两个部分。同一项目中的API和网络应用程序。它还有两个DbContext
,DbContext1
和DbContext2
;因此有两组身份用户。对于每两个用户,一个用户必须从另一个DbContext1
进行身份验证才能访问另一个DbContex2
。另外,DbContext2
由DbContext1
初始化。我已经使授权与使用Cookie身份验证的Web应用程序一起正常工作,但是授权不适用于API。
我使用授权属性[Authorize(Roles="AdminDb2,SupervisorDb2")]
设计了API控制器
但后来没有任何效果。出现问题了。我的默认身份存储使用DbContext1
作为其身份存储,这意味着DbContext2
的用户无法获得授权。是的,我使用JWT Authentication
的事实也无济于事。另外,我还必须转到我的startup
文件并执行以下操作
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<Db1User, Db1Role>()
.AddEntityFrameworkStores<DbContext1>()
.AddRoleManager<Db1RoleManager>()
.AddSignInManager<Db1SignInManager>()
.AddUserManager<DbAuthenticationManager>()
.AddDefaultTokenProviders()
.AddDefaultUI(Microsoft.AspNetCore.Identity.UI.UIFramework.Bootstrap4);
}
,还通过致电添加了第二个身份
services.AddIdentityCore<Db2User>()
没有任何效果。
经过数天的思考,虽然授权不起作用,但我发现Identity存储正在尝试使用DbContext1
对用户进行授权。好的,现在我明白了。我现在发现基于策略的授权很有用。
现在,我在startup
文件中完成了此操作
services.AddAuthorization(options =>
{
options.AddPolicy("SuperPolicy", pOptions =>
{
pOptions.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
pOptions.Requirements.Add(new ApiRequirement("Admin,SuperAdmin"));
});
}
然后我必须使用首选的方法来处理这样的授权
public class ApiRequirement : IAuthorizationRequirement
{
public string[] Requirements { get; }
public ApiRequirement(params string[] requirements)
{
Requirements = requirements;
}
}
public class ApiAuthorizeHandler: AuthorizationHandler<ApiRequirement>
{
private readonly TokenValidator _tokenValidator;
public ApiAuthorizeHandler(TokenValidator tokenValidator)
{
_tokenValidator = tokenValidator;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ApiRequirement requirement)
{
AuthorizationFilterContext filterContext = (AuthorizationFilterContext)context.Resource;
string authToken = filterContext.HttpContext.Request.Headers["Authorization"];
TokenValidator validationResult = _tokenValidator.ValidateToken(authToken);
bool result = validationResult.IsInRole(requirement.Requirements);
if (result)
{
context.Succeed(requirement);
context.User.AddIdentity(validationResult.ClaimsPrincipal.Identities.First());
return Task.CompletedTask;
}
context.Fail();
return Task.CompletedTask;
}
}
有了这个,我不需要编写新的授权过滤器
然后我用通常的Authorize过滤器设计了控制器
[Authorize(Policy="SuperPolicy")]
public class MyController : ControllerBase
{
}
我发现此方法的一件事是,每当您想向属性添加角色或要求时,都必须转到注入授权的启动文件,并执行options.AddPolicy().....
这样的启动工作文件开始看起来不整洁。但是,如果不是那样的话,那么它随时随地都很好。
我发现这种共享想法可能会有所帮助。