一.概述
ASP.NET核心MVC提供基于角色、Chaim和策略的授权方式。在实际应用中,授权可以通过部门(本文中的用户组)、职位(角色可以继续)、权限等方式进行。为了实现这一目标,不可能只定制IAuthorizationPolicyProvider。本文通过定制IApplicationModelProvide进行了扩展。
第二,permissionauthorizeattribute:ipermisteruthorizedata
AuthorizeAttribute类实现IAuthorizeData接口:
namespace Microsoft.AspNetCore.Authorization{
/// <。摘要>。
///定义将授权规则应用于资源所需的数据集。
/// <。/summary>。
公共接口IAuthorizeData
{
/// <。摘要>。
///获取或设置确定对资源的访问权限的策略名称。
/// <。/summary>。
字符串策略{ get设置;}
/// <。摘要>。
///获取或设置允许访问资源的角色的逗号分隔列表。
/// <。/summary>。
字符串角色{ get设置;}
/// <。摘要>。
///获取或设置以逗号分隔的方案列表,从中构造用户信息。
/// <。/summary>。
string AuthenticationSchemes { get;设置;}
}
}
AuthorizeAttribute的使用只不过是以下几种形式:
[Authorize][授权(“某些政策”)]
[授权(角色=“角色1,角色2”)]
[Authorize(AuthenticationSchemes = JwtBearerDefaults。AuthenticationScheme)]
当然,参数也可以组合。此外,角色和身份验证架构的值由逗号分隔,这是或的关系;许多“授权”处于“与”的关系中;如果同时使用策略、角色和身份验证方案,它们也处于和的关系中。
要扩展AuthorizeAttribute,首先扩展IAuthorizeData以添加新属性:
public interface IPermissionAuthorizeData : IAuthorizeData{
字符串组{ get设置;}
字符串权限{ get设置;}
}
然后定义AuthorizeAttribute:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]公共类PermissionAuthorizeAttribute:属性,IPermissionAuthorizeData
{
公共字符串策略{ get设置;}
公共字符串角色{ get设置;}
公共字符串身份验证架构{ get设置;}
公共字符串组{ get设置;}
公共字符串权限{ get设置;}
}
现在,它可以在控制器或操作上使用,如下所示:
[PermissionAuthorize(Roles = "经理,副经理")] // 经理或部门经理【权限权限(group = " R&D部门,生产部门",Roles = "经理" 】//R&D部门经理或代部门经理。组和角色是“和”。
【权限权限(group = " R&D部门,生产部门",Roles = "经理",Permissions = "请假审批"】//R&D部门经理或生产部门经理,有请假审批权限。组、角色和权限是“和”关系。
数据准备好了,下一步就是如何提取。可以通过扩展授权应用modelprovider来实现。
三.许可授权应用程序模型提供程序:应用程序模型提供程序
authorizationapplicationmodelprovider类的作用是构造AuthorizeFilter对象,并将其放入ControllerModel或ActionModel的Filters属性中。具体过程是提取实现IAuthorizeData接口的控制器和动作的属性。如果使用默认的授权策略提供程序,将创建一个授权策略对象作为AuthorizeFilter构造函数的参数。
授权策略对象由授权策略的静态方法公共静态异步任务创建
因为authorizationapplicationmodelprovider类依赖于authorizationpolicy。combineasync静态方法,我们要在这里做一个类似permissionautorizationapplicationmodelprovider的类,在这个类中实现CombineAsync方法。先不说这个方法是否适合这个类别。
public static AuthorizeFilter GetFilter(IAuthorizationPolicyProvider policyProvider, IEnumerable<IAuthorizeData> authData){
//默认策略提供者会为给定的输入制定相同的策略,所以只制定一次。
//这将始终同步执行。
if (policyProvider。GetType()= = type of(DefaultAuthorizationPolicyProvider))
{
var policy = CombineAsync(policy provider,authData)。geta服务员()。GetResult();
返回新的AuthorizeFilter(策略);
}
其他
{
返回新的授权过滤器(策略提供者,授权数据);
}
}
私有静态异步任务& lt授权策略>。CombineAsync(iauthorizationpolicy provider policy provider,IEnumerable & ltIAuthorizeData & gtauthorizeData)
{
if (policyProvider == null)
{
引发新的ArgumentNullException(name of(PolicyProvider));
}
if (authorizeData == null)
{
引发新的ArgumentNullException(name of(authorizeData));
}
var PolicyBuilder = new authorizationPolicyBuilder();
var any = false
foreach(var authorized atum in authorized data)
{
any = true
var useDefaultPolicy = true
if(!字符串。isnullorhitespace(authorized usual。政策))
{
var policy = await policyProvider。GetPolicyAsync(AuthorizedItalum。政策);
if(策略== null)
{
//抛出新的InvalidOperationException(参考资料。format exception _ authorizationpolicy not found(authorized torm。政策));
引发新的InvalidOperationException(名称为(authorizeDatum)。政策));
}
policyBuilder。合并(政策);
useDefaultPolicy = false
}
var rolesSplit = authorizeDatum。角色?。Split(',');
if (rolesSplit!= null & amp& amp角色点亮。Any())
{
var trimmedRolesSplit = rolesSplit。其中(r = & gt!字符串。isnullorhitespace(r))。选择(r = & gtr . Trim());
policyBuilder。require role(triedlesplit);
useDefaultPolicy = false
}
if(authorized torm是ipermisterauthorized data permissional authorized torm)
{
var groups slit = Permissionauthorized trum。团体?。Split(',');
if(GroupSplit!= null & amp& ampgroupsSplit。Any())
{
var TrimbedGroupSplit = GroupSplit。其中(r = & gt!字符串。isnullorhitespace(r))。选择(r = & gtr . Trim());
policyBuilder。required claim(" Group ",triedgroupsplit);// TODO:注意硬编码
useDefaultPolicy = false
}
var Permissions slit = Permissionauthorized trum。权限?。Split(',');
if(Permissions Lit!= null & amp& amppermissionsSplit。Any())
{
var triedpermissionssplit = permissionsSplit。其中(r = & gt!字符串。isnullorhitespace(r))。选择(r = & gtr . Trim());
policyBuilder。required claim(" Permission ",triedpermissionsPlit);// TODO:注意硬编码
useDefaultPolicy = false
}
}
var AuthTypeSplit = AuthorizedItum。身份验证方案?。Split(',');
if(authtysplit!= null & amp& ampauthTypesSplit。Any())
{
foreach(在authTypesSplit中的变量验证类型)
{
if(!字符串。isnullorhitespace(authType))
{
policyBuilder。身份验证架构。添加(身份验证类型。trim());
}
}
}
if (useDefaultPolicy)
{
policyBuilder。合并(等待策略提供商。getDefaultPolicyAsync());
}
}
退货吗?policyBuilder。build():null;
}
如果(授权数据是网上授权数据许可授权状态)是一个扩展。
四.启动
要注册权限授权应用程序模型提供程序服务,您需要在添加Mvc后替换授权应用程序模型提供程序服务。
services.AddMvc();服务。Replac(ServiceDeor。瞬态<。IApplicationModelProvider,Permissionauthorizationapplicationmodelprovider & gt;());
五、Jwt 示例[Route("api/[controller]")][速度控制器]
公共类值控制器:控制器数据库
{
private readonly Jwtsecuritytokenhandler _ token handler = new Jwtsecuritytokenhandler();
[HttpGet]
[路线(“登录”)]
公共异步任务& ltActionResult<。string>。>。登录()
{
var user = new ClaimSprincipal(new ClaimSidenty(new[]
{
//注意:声明类型:组和权限在这里是硬编码的,应该定义为类似于声明类型的常量。角色;此外,以下模拟数据可能不符合逻辑。
新索赔类型。姓名,“鲍勃”),
新索赔类型。角色,“经理”),//注意:不能用逗号分隔多个角色,下同。
新索赔类型。角色,“副经理”),
新索赔(“集团”、“R&D部”),
新索赔(“集团”、“生产部门”),
新申请(“许可”、“许可”),
新声明(“许可”、“许可1”),
新声明(“许可”、“许可2”),
},JwtBearerDefaults。AuthenticationScheme));
var token = new JwtSecurityToken(
“信号和验证示例”,
“信号和验证示例”,
用户。索赔,
过期时间:DateTime。现在。添加天数(30),
签名证书:签名帮助。generatedesigningcredentials(" 1234567890123456 ");
return _tokenHandler。write token(token);
}
[HttpGet]
[路线(“测试”)]
【权限权限(group = " R&D部门,生产部门",Roles = "经理",Permissions = "请假审批"】//R&D部门经理或生产部门经理,有请假审批权限。组、角色和权限是“和”关系。
公共异步任务& ltActionResult<。IEnumerable<。string>。>。>。测试()
{
var user = HttpContext。用户;
返回新字符串[] { "value1 "," value 2 " };
}
}
六、问题AuthorizeFilter类显示实现IFilterFactory接口的CreateInstance方法:
IFilterMetadata IFilterFactory.CreateInstance(IServiceProvider serviceProvider){
如果(政策!= null || PolicyProvider!= null)
{
//过滤器已完全构建。使用当前实例进行授权。
归还这个;
}
调试。Assert(AuthorizeData!= null);
var PoLicy Provider = ServiCe Provider。GetRequiredService<。iauthorizationpolicy provider & gt。();
返回AuthorizationApplicationModelProvider。GetFilter(policyProvider,AuthorizeData);
}
出乎意料的是,它依赖于authorizationapplicationmodelprovider . getfilter的静态方法..幸运的是,如果授权过滤器(iauthorization policy provider,ienumerable
七、下一步
[PermissionAuthOrize(group = " R&D部门,生产部门",Roles = "经理",Permissions = "请假审批"]仍然不够灵活,即使使用了多个Attribute,and,And或or的逻辑组合也不一定能满足需求。您可以在网上授权数据中添加一个规则属性,以达到类似的效果:
[PermissionAuthorize(Rule = "(Groups:研发部,生产部)&&(Roles:请假审批||Permissions:超级权限)"]复杂授权按规则计算。
八、如果通过自定义IAuthorizationPolicyProvider?
另一种方法是自定义IAuthorizationPolicyProvider,但您还需要自定义AuthorizeFilter。因为当您自定义IAuthorizationPolicyProvider而不是DefaultAuthorizationPolicyprovider时,authorizationapplicationmodeprovider(或上面定义的permissionautorizationapplicationmodeprovider)使用authorizefilter(IAuthorizationPolicyProvider,ienumerable
这可以说是一个设计缺陷,静态方法authorizationpolicy。combineasync不应该存在,即使提供了IAuthorizationPolicyCombiner。另外,上面提到的authorizationapplicationmodelprovider . get filter的静态方法也不是很好的设计。等微软想明白了再说。
参考数据
https://docs . Microsoft . com/zh-cn/aspnet/core/security/authorization/iauthorizationpolicy provider?view=aspnetcore-2.1
排版问题:http://blog . tubumu . com/2018/11/28/aspnetcore-MVC-extend-authorization/
1.《authorize ASP.NET Core MVC 授权的扩展:自定义 Authorize 和 IApplicationModelProvide》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《authorize ASP.NET Core MVC 授权的扩展:自定义 Authorize 和 IApplicationModelProvide》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/junshi/1522373.html