今天学习下jwt,遇到了两个坑爹问题,这里记录下。在 asp.net core 中,授权的设置方式有两种,可以使用角色,也可以使用策略,这里也将简单举例角色、策略的使用。

jwt这里不做介绍,如果想了解更多,请看https://www.jianshu.com/p/a12fc67c9e05,https://www.cnblogs.com/createmyself/p/11123023.html ,这两篇都讲解的很好,这里只写实际的使用和遇到的问题。

1. jwt的secretkey必须16位以上

jwt中key必须16位以上,否则长度不够会抛出异常,异常代码如下

system.argumentoutofrangeexception
  hresult=0x80131502
  message=idx10603: decryption failed. keys tried: '[pii is hidden. for more details, see https://aka.ms/identitymodel/pii.]'.
exceptions caught:
 '[pii is hidden. for more details, see https://aka.ms/identitymodel/pii.]'.
token: '[pii is hidden. for more details, see https://aka.ms/identitymodel/pii.]' 
  source=microsoft.identitymodel.tokens
  stacktrace:
   at microsoft.identitymodel.tokens.symmetricsignatureprovider..ctor(securitykey key, string algorithm, boolean willcreatesignatures)
....................

2.获取token之后,一直401unauthorized

在startup.cs中的configure中添加app.useauthentication();新创建.net core项目的时候,会自动添加授权app.useauthorization();但是jwt其实是一种认证,准确;来说是登录的过程,需要用户名和密码的认证。

例如:你要登陆论坛,输入用户名张三,密码1234,密码正确,证明你张三确实是张三,这就是 认证authentication;那么是否有删除添加等的操作,这就是授权authorization

3.jwttoken的获取

//appsettings.json中增加配置信息
"jwtsettings": {
    "issuer": "https://localhost:44378/",
    "audience": "https://localhost:44378/",
    "secretkey": "1234567890123456"
  }
// startup.cs中增加jwt的设置           
            services.addauthentication(options =>
            {
                //认证middleware配置
                options.defaultauthenticatescheme = jwtbearerdefaults.authenticationscheme;
                options.defaultchallengescheme = jwtbearerdefaults.authenticationscheme;
            })
            .addjwtbearer(o =>
            {
                //主要是jwt  token参数设置
                o.tokenvalidationparameters = new tokenvalidationparameters
                {
                    //token颁发机构
                    validissuer = jwtsettings.issuer,
                    //颁发给谁
                    validaudience = jwtsettings.audience,
                    //这里的key要进行加密,需要引用microsoft.identitymodel.tokens
                    issuersigningkey = new symmetricsecuritykey(encoding.utf8.getbytes(jwtsettings.secretkey)),
                    validateissuersigningkey = true,
                    //是否验证token有效期,使用当前时间与token的claims中的notbefore和expires对比
                    validatelifetime = true,
                    //允许的服务器时间偏移量
                    clockskew = timespan.zero

                };
            });
// controller中获取token       
        [httppost]
        public iactionresult token(loginmodel login)
        {
            _logger.loginformation($"获取token:user:{login.user}");
            if (string.isnullorempty(login.user) || string.isnullorempty(login.password))//判断账号密码是否正确
            {
                return badrequest();
            }


            var claim = new list<claim>{
                    new claim(claimtypes.name,login.user),
                    new claim(claimtypes.role,"test")
                };

            //建立增加策略的授权
            if (login.user == "test") claim.add(new claim("test", "test"));
            if (login.user == "test1") claim.add(new claim("test", "test1"));
            if (login.user == "test2") claim.add(new claim("test", "test2"));
            if (login.user == "test3") claim.add(new claim("test", "test3"));

            //对称秘钥
            var key = new symmetricsecuritykey(encoding.utf8.getbytes(_jwtsettings.secretkey));
            //签名证书(秘钥,加密算法)
            var creds = new signingcredentials(key, securityalgorithms.hmacsha256);

            //生成token  [注意]需要nuget添加microsoft.aspnetcore.authentication.jwtbearer包,并引用system.identitymodel.tokens.jwt命名空间
            var token = new jwtsecuritytoken(_jwtsettings.issuer, _jwtsettings.audience, claim, datetime.now, datetime.now.addminutes(30), creds);

            return ok(new { token = new jwtsecuritytokenhandler().writetoken(token) });
        }

4.基于角色的授权

        [httpget]
        [authorize(roles ="test")]
        public actionresult<string> authvalue()
        {
            var name = user.findfirst(claimtypes.name)?.value;
            var role = user.findfirst(claimtypes.role)?.value;
            _logger.loginformation($"权限登录,用户名:{name},角色:{role}");

            return $"权限登录,用户名:{name},角色:{role}";
        }
roles角色如果有多个,可以以逗号隔开。

5.基于策略的授权

//startup.cs中添加策略
services.addauthorization(options => { options.addpolicy("onlytestaccess", policy => policy.requireclaim("test", new string[] { "test1", "test2" })); options.addpolicy("departmentaccess", policy => policy.requireclaim("department")); });
        // 方法上增加策略    
[httpget] [authorize(policy = "onlytestaccess")] public actionresult<string> authextensionvalue() { var name = user.findfirst(claimtypes.name)?.value; var role = user.findfirst(claimtypes.role)?.value; _logger.loginformation($"基于策略的登录,用户名:{name},角色:{role}"); return $"基于策略的登录,用户名:{name},角色:{role}"; }

6.运行的截图


7.github上的源码

https://github.com/jasonhua95/samll-project/tree/master/jwtapidemo