您的位置:首页 > 编程语言 > ASP

ASP.NET Core的JWT的实现(自定义策略形式验证).md

2019-03-19 11:58 627 查看

既然选择了远方,便只顾风雨兼程 __ HANS许

在上篇文章,我们讲了JWT在ASP.NET Core的实现,基于中间件来实现。这种方式有个缺点,就是所有的URL,要嘛需要验证,要嘛不需要验证,没有办法各取所需,因为我们某个API与另一个API的验证方式不一样。这就引导出“基于自定义策略形式下的验证了”。

ASP.NET Core 的Authorization实现

我们使用Core自带的Authorization(认证与授权)来实现。大家可以先看下微软官方的策略授权

  1. 微软官方例子:
    1.1 定义策略

    [li]internal class MinimumAgeAuthorizeAttribute : AuthorizeAttribute 
  2. { [/li]
  3. const string POLICY_PREFIX = "MinimumAge"; 
  4. public MinimumAgeAuthorizeAttribute(int age) => Age = age; 
  5. // Get or set the Age property by manipulating the underlying Policy property 
  6. public int Age 
  7. get 
  8. if (int.TryParse(Policy.Substring(POLICY_PREFIX.Length), out var age)) 
  9. return age; 
  10. return default(int); 
  11. set 
  12. Policy = $"{POLICY_PREFIX}{value.ToString()}"; 

1.2 使用策略

  1. [MinimumAgeAuthorize(10)] 
  2. 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

      [li]public class JwtAuthorizeBaseRequiremente : IJwtAuthorizRequiremente  { [/li]
    1. protected internal Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad = (a, b) => 
    2. return true; 
    3. }; 
    4.  
    5. public virtual IJwtAuthorizRequiremente SetValidateFunc(Func<Dictionary<string, string>, JsonWebTokenSetting, bool> func) 
    6.  
    7. this.validatePayLoad = func ?? this.validatePayLoad; 
    8. return this; 

    2.3 了解

    AuthorizationHandler

    AuthorizationHandler
    为特定需求类型调用的授权处理程序的基类。也就是说我们处理策略是会到这个基类来处理,并且判断是否认证成功,也就是授权成功。

    2.4 继承

    AuthorizationHandler

    JwtAuthorizeHandler
    继承
    AuthorizationHandler
    并实现泛型
    JwtAuthorizeBaseRequiremente
    的定义,这样子我们的自定义的策略委托验证函数就会传递到这个处理类。我们需要重写
    HandleRequirementAsync
    来自定已处理。可以看到,最终我们还是调用上篇文章所讲的验证函数
    _jsonWebTokenValidate.Validate
    ,大家不清楚可以去看上篇文章。而
    requirement.validatePayLoad
    便是我们稍后再外面自定义的验证函数了。

    1. public class JwtAuthorizeHandler : AuthorizationHandler<JwtAuthorizeBaseRequiremente> 
    2. private readonly JsonWebTokenSetting _setting; 
    3. private readonly IJsonWebTokenValidate _jsonWebTokenValidate; 
    4.  
    5. public JwtAuthorizeHandler(IOptions<JsonWebTokenSetting> setting, IJsonWebTokenValidate jsonWebTokenValidate) 
    6. this._setting = setting.Value; 
    7. this._jsonWebTokenValidate = jsonWebTokenValidate; 
    8.  
    9. /// <summary> 
    10. /// 验证JWT 
    11. /// </summary> 
    12. /// <param name="context"></param> 
    13. /// <param name="requirement"></param> 
    14. /// <returns></returns> 
    15. protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, JwtAuthorizeBaseRequiremente requirement) 
    16. var httpContext = (context.Resource as AuthorizationFilterContext).HttpContext; 
    17.  
    18. var result = httpContext.Request.Headers.TryGetValue("Authorization", out StringValues authStr); 
    19. if (!result || string.IsNullOrEmpty(authStr.ToString())) 
    20. throw new UnauthorizedAccessException("未授权,请传递Header头的Authorization参数。"); 
    21. result = result && _jsonWebTokenValidate.Validate(authStr.ToString().Substring("Bearer ".Length).Trim(), _setting, requirement.validatePayLoad); 
    22. if (!result) 
    23. throw new UnauthorizedAccessException("验证失败,请查看传递的参数是否正确或是否有权限访问该地址。"); 
    24. context.Succeed(requirement); 
    25. return Task.CompletedTask; 

    2.5 怎么使用呢?

    • 我们需要在

      Startup.cs
      文件进行注册服务。其中
      CommonAuthorize
      继承
      JwtAuthorizeBaseRequiremente
      ,并将自定义的策略方法,传递进去。其中
      common
      是策略名称。可以多个定义策略

        [li]public void ConfigureServices(IServiceCollection services)  { [/li]
      1. services.AddJwt(Configuration); 
      2. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 
      3. services.AddAuthorization(option => 
      4. #region 自定义验证策略 可以一直自定义策略 
      5. option.AddPolicy("common", policy => policy.Requirements.Add(new CommonAuthorize(). 
      6. SetValidateFunc((playLoad, sertting) => 
      7. //每个策略自定义验证函数,playLoad为带过来的参数字典,setting为失效时间与秘钥 
      8. return true; 
      9. }))); 
      10. #endregion 自定义验证策略 
      11. }).AddAuthentication(option => 
      12. option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; 
      13. }); 
      14. }  
    • 接着我们在想要的

      Controller
      或者
      Action
      的头部使用
      [Authorize(Policy = "common")]
      ,这样每次进到相对应的
      Controller
      或者
      Action
      ,会先进行策略验证,而我们这边验证的便是JWT了。

    总结一下,我们在这篇文章是基于上篇文章的,所以JWT的生成与验证我们就不讲了。两篇文章讲了JWT的验证,两种方式有好有坏,大家可以根据自己的模式进行选择。

    1.使用管道的方式,感觉方便点,清晰点
    2. 使用自定义策略的方式,效率稍微高一点,毕竟不是所有的请求都会进行是否可以匿名访问运算和建立管道的消耗,只有加入Authorize属性的Controller和Action的才会进入

    最后附上源码,或者直接到我的GitHub上看看。后面要是有时间,可以讲下

    IdentityServer4
    的OAuth2的授权与认证。

  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: