既然选择了远方,便只顾风雨兼程 __ HANS许
在上篇文章,我们讲了JWT在ASP.NET Core的实现,基于中间件来实现。这种方式有个缺点,就是所有的URL,要嘛需要验证,要嘛不需要验证,没有办法各取所需,因为我们某个API与另一个API的验证方式不一样。这就引导出“基于自定义策略形式下的验证了”。
ASP.NET Core 的Authorization实现
我们使用Core自带的Authorization(认证与授权)来实现。大家可以先看下微软官方的策略授权
-
微软官方例子: 1.1 定义策略
-
internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute?
- {?
- const string POLICY_PREFIX = "MinimumAge";?
- public MinimumAgeAuthorizeAttribute(int age) => Age = age;?
- ?
- public int Age?
- {?
- get?
- {?
- if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length),out var age))?
- {?
- return age;?
- }?
- return default(int);?
- }?
- set?
- {?
- Policy = $"{POLICY_PREFIX}{value.ToString()}";?
- }?
- }?
- }?
1.2 使用策略
- [MinimumAgeAuthorize(10)]?
-
public IActionResult RequiresMinimumAge10()?
这样在执行RequiresMinimumAge10 会先执行MinimumAgeAuthorize 策略,很像MVC的Attribute 特性, 但内部又不像,在这边就不多做解释了,微软的Core官方文档讲的很清楚。大家去看下就清楚了。
-
JWT的自定义策略形式的实现 2.1 了解IAuthorizationRequirement
IAuthorizationRequirement 表示授权要求,用户可以继承这个接口,实现自己认证与授权的要求,比如上面的片段代码,它就继承该接口,并有个字段Age ,也就是这个策略有年龄的要求,这个要求可以带到我们后面验证的方法里面。我们往下看。 2.2 继承IAuthorizationRequirement 所以我们实现了JwtAuthorizeBaseRequiremente 该接口,并继承IAuthorizationRequirement ,可以看到我们的要求是一个叫validatePayLoad 的委托函数,委托函数的入参是字典,JWT,字典便是上篇文章说的JWT的负载部分了。而返回参数是bool,便代表我们自定义的策略验证JWT是否成功。IJwtAuthorizRequiremente 继承了IAuthorizationRequirement
-
public class JwtAuthorizeBaseRequiremente : IJwtAuthorizRequiremente?
- {?
- protected internal Func<Dictionary<string,string>,JsonWebTokenSetting,bool> validatePayLoad = (a,b) =>?
- {?
- return true;?
- };?
- ?
- public virtual IJwtAuthorizRequiremente SetValidateFunc(Func<Dictionary<string,bool> func)?
- ?
- {?
- this.validatePayLoad = func ?? this.validatePayLoad;?
- return this;?
- }?
- }?
2.3 了解AuthorizationHandler
AuthorizationHandler 为特定需求类型调用的授权处理程序的基类。也就是说我们处理策略是会到这个基类来处理,并且判断是否认证成功,也就是授权成功。 2.4 继承JwtAuthorizeHandler 继承AuthorizationHandler 并实现泛型JwtAuthorizeBaseRequiremente 的定义,这样子我们的自定义的策略委托验证函数就会传递到这个处理类。我们需要重写HandleRequirementAsync 来自定已处理。可以看到,最终我们还是调用上篇文章所讲的验证函数_jsonWebTokenValidate.Validate ,大家不清楚可以去看上篇文章。而requirement.validatePayLoad 便是我们稍后再外面自定义的验证函数了。
- public class JwtAuthorizeHandler : AuthorizationHandler<JwtAuthorizeBaseRequiremente>?
- {?
- private readonly JsonWebTokenSetting _setting;?
- private readonly IJsonWebTokenValidate _jsonWebTokenValidate;?
- ?
- public JwtAuthorizeHandler(IOptions<JsonWebTokenSetting> setting,IJsonWebTokenValidate jsonWebTokenValidate)?
- {?
- this._setting = setting.Value;?
- this._jsonWebTokenValidate = jsonWebTokenValidate;?
- }?
- ?
- ?
- ?
- ?
- ?
- ?
- ?
- protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,JwtAuthorizeBaseRequiremente requirement)?
- {?
- var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext;?
- ?
- var result = httpContext.Request.Headers.TryGetValue("Authorization",out StringValues authStr);?
- if (!result || string.IsNullOrEmpty(authStr.ToString()))?
- {?
- throw new UnauthorizedAccessException("未授权,请传递Header头的Authorization参数。");?
- }?
- result = result && _jsonWebTokenValidate.Validate(authStr.ToString().Substring("Bearer ".Length).Trim(),_setting,requirement.validatePayLoad);?
- if (!result)?
- {?
- throw new UnauthorizedAccessException("验证失败,请查看传递的参数是否正确或是否有权限访问该地址。");?
- }?
- context.Succeed(requirement);?
- return Task.CompletedTask;?
- }?
- }?
2.5 怎么使用呢?
-
我们需要在Startup.cs 文件进行注册服务。其中CommonAuthorize 继承JwtAuthorizeBaseRequiremente ,并将自定义的策略方法,传递进去。其中common 是策略名称。可以多个定义策略
-
public void ConfigureServices(IServiceCollection services)?
- {?
- services.AddJwt(Configuration);?
- services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);?
- services.AddAuthorization(option =>?
- {?
- #region 自定义验证策略 可以一直自定义策略?
- option.AddPolicy("common",policy => policy.Requirements.Add(new CommonAuthorize().?
- SetValidateFunc((playLoad,sertting) =>?
- {?
- ?
- return true;?
- })));?
- #endregion 自定义验证策略?
- }).AddAuthentication(option =>?
- {?
- option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;?
- });?
- } ?
-
接着我们在想要的Controller 或者Action 的头部使用[Authorize(Policy = "common")] ,这样每次进到相对应的Action ,会先进行策略验证,而我们这边验证的便是JWT了。
总结一下,我们在这篇文章是基于上篇文章的,所以JWT的生成与验证我们就不讲了。两篇文章讲了JWT的验证,两种方式有好有坏,大家可以根据自己的模式进行选择。
1.使用管道的方式,感觉方便点,清晰点 2. 使用自定义策略的方式,效率稍微高一点,毕竟不是所有的请求都会进行是否可以匿名访问运算和建立管道的消耗,只有加入Authorize属性的Controller和Action的才会进入
最后附上源码,或者直接到我的GitHub上看看。后面要是有时间,可以讲下IdentityServer4 的OAuth2的授权与认证。
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|