码迷,mamicode.com
首页 > Web开发 > 详细

.netCore下的jwt的梳理-->借鉴于“老张的哲学”

时间:2019-11-18 09:41:22      阅读:108      评论:0      收藏:0      [点我收藏+]

标签:ons   new   class   tco   fss   new t   returns   txt   token   

       之前在公司的项目中有用到jwt进行token验证,但是公司里用的框架已经集成好了jwt,所以对jwt的的了解不够清晰,感觉还是隔着一层。在看了“老张的哲学”的jwt部分后对jwt的认识才更加深刻了一些,这篇文章主要是自己对知识的一个梳理。

  1.   Jwt的介绍
  2.        swagger中启用jwt
  3.        配置jwt官方认证 
  4.        例子

       1、jwt的组成

       jwt通常由三部分组成,(1)头部 Header、(2)消息载体 payload、(3)签名 signature   由.号隔开三部分  例如

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

       1)Header一般由两个部分组成:alg和typ

   alg是所使用的hash算法,如:HMAC SHA256或RSA,typ是Token的类型,在这里就是:JWT,然后使用Base64Url编码成第一部分:

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
{
  "alg": "HS256",
  "typ": "JWT"
}

     2)payload这一部分是JWT主要的信息存储部分,主要由各种claims(声明/信息)组成

   在JwtRegisteredClaimNames(微软预先定义的)类中包含了一些常用的信息,例如:Jti(编号)、Iat(签发时间)、Exp(过期时间)、Iss(签发人)、Aud(订阅者)等

    一个简单的Pyload可以是这样子的,同样使用Base64Url编码成第二部分::

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

  3)signature 签名,通过服务端的密钥生成,用来验证生成的jwt是不是有效的,最后生成的jwt

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

 2、Swagger中启用jwt 注意是swagger服务内部

 api文档用的是swagger,所以还需要在startup里的swagger配置中启用jwt的配置,swagger的具体配置使用就不放在这边,准备以后结合公司的方式在补充一篇。 

  在ConfigureServices下的swagger中配置jwt

          #region Swagger

            services.AddSwaggerGen(c =>
            {
                #region swagger的配置
                
                c.SwaggerDoc("v1",new Info
                {
                    Version = "v0.1.0",
                    Title = "Blog.Core API",
                    Description = "框架说明文档"
                });
                var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
                var xmlPath = Path.Combine(basePath, "Blog.Core.xml");
                c.IncludeXmlComments(xmlPath,true);//默认的第二个参数是false,这个是controller的注释,记得修改

                var xmlModelPath = Path.Combine(basePath, "Blog.Core.Model.xml");
                c.IncludeXmlComments(xmlModelPath);
                #endregion

                #region swagger 中开启jwt认证
                //添加header验证信息
                var security = new Dictionary<string, IEnumerable<string>> { { "Blog.Core", new string[] { } } };
                c.AddSecurityRequirement(security);
                c.AddSecurityDefinition("Blog.Core", new ApiKeyScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)",
                    Name = "Authorization",
                    In = "header",
                    Type = "apiKey"
                });

                #endregion

            });

            #endregion   

       3、配置官方jwt

       在swagger开启jwt认证后,还需要配置jwt中间件(用来解析收到jwt是否有效),我用的官方默认配置

       在appsettings.json中的配置(可以改进,感觉还是根据环境变量配置比较好即放入(appsettings.Development.json)文件中,中间的Development根据环境改变)

  "Audience": {
    "Secret": "sdfsdfsrty45634kkhllghtdgdfss345t678fs", //不要太短,请注意!!!16+
    "SecretFile": "C:\\my-file\\blog.core.audience.secret.txt",
    "Issuer": "Blog.Core",
    "Audience": "wr"
  }  

       在ConfigureServices中配置

      #region jwt 官方认证
            //密钥的生成
            var audienceConfig = Configuration.GetSection("Audience");
            var symmetricKeyAsBase64 = audienceConfig["Secret"];  //从配置中读取密钥  注意:密钥长度需要大于16位
            var KeyByteArray = Encoding.UTF8.GetBytes(symmetricKeyAsBase64);
            var signingKey =  new SymmetricSecurityKey(KeyByteArray);

            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,
                ValidateIssuer = true,
                ValidIssuer = audienceConfig["Issuer"],//发行人
                ValidateAudience = true,
                ValidAudience = audienceConfig["Audience"],//订阅人
                ValidateLifetime = true,
                RequireExpirationTime = true,
            };

            //主要部分
            services.AddAuthentication("Bearer")
                .AddJwtBearer(option =>
                {
                    option.TokenValidationParameters = tokenValidationParameters;
                });

            #endregion

  

       在configure 中配置,启用jwt官方中间件

 //如果你想使用官方认证,必须在上边ConfigureService 中,配置JWT的认证服务 (.AddAuthentication 和 .AddJwtBearer 二者缺一不可)
 app.UseAuthentication();

  4、例子

       在配置完成之后服务端需要提供一个GetToken(获取生成的jwt)的方法给前端,在需要使用认证的接口加上特性标签表示启用检测jwt是否有用

例(老方法,之后有空了补充新的生成jwt方法,加上refreshToken,避免token过期问题):

    [Route("api/Blog")]
    [Authorize]
    public class BlogController : Controller
    {
        // GET: api/Blog/5
        [HttpGet("GetToken")]
        [AllowAnonymous]
        public string GetToken()
        {
            TokenModelJwt tokenModel = new TokenModelJwt
            {
                Role="Admin",
                Uid=1,
                Work=""
            };
            return JwtHelper.IssueJwt(tokenModel); ;
        }
    }

 

  

      /// <summary>
        /// 颁发token
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJwt(TokenModelJwt tokenModel)
        {
            // 自己封装的 appsettign.json 操作类,看下文
            string iss = Appsettings.app(new string[] { "Audience", "Issuer" }); //iss: 签发人
            string aud = Appsettings.app(new string[] { "Audience", "Audience" });//aud: 受众
            string secret = Appsettings.app(new string[] { "Audience", "Secret" });

            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Jti,tokenModel.Uid.ToString()),//jti: 编号
                new Claim(JwtRegisteredClaimNames.Iat,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds()}"),//Iat 签发时间
                //new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeMilliseconds()}"),//nbf: 生效时间
                new Claim(JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeMilliseconds()}"),//exp: 过期时间
                //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
                new Claim(JwtRegisteredClaimNames.Iss,iss),
                new Claim(JwtRegisteredClaimNames.Aud,aud)
            };
            //// 可以将一个用户的多个角色全部赋予;
            claims.AddRange(tokenModel.Role.Split(‘,‘).Select(e=>new Claim(ClaimTypes.Role,e)));
            //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)

            var key=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds=new SigningCredentials(key,SecurityAlgorithms.HmacSha256);

            var jwt = new JwtSecurityToken(
                issuer: iss,
                audience: aud,
                claims: claims,
                expires:DateTime.Now.AddHours(1),
                signingCredentials: creds);

            var jwtHandler = new JwtSecurityTokenHandler();
            var encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

  补充Appsetings类(有空了修改更加简介的方式),使用记得去Startup里面注入,注入方法:services.AddSingleton(new Appsettings(Env.ContentRootPath));

  public class Appsettings
    {
        static IConfiguration Configuration { get; set; }
        static string contentPath { get; set; }

        public Appsettings(string contentPath)
        {
            //如果你把配置文件 是 根据环境变量来分开了,可以这样写
            string Path = $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json";

            //string Path = "appsettings.json";

            Configuration = new ConfigurationBuilder()
                .SetBasePath(contentPath)
                .Add(new JsonConfigurationSource {Path = Path, Optional = false, ReloadOnChange = true})
                .Build();
        }

        public static string app(params string[] sections)
        {
            try
            {
                if (sections.Any())
                {
                    return Configuration[string.Join(":", sections)];
                }
            }
            catch (Exception) { }
            return "";
        }
    }

  最后,以上代码大部分使用的是“老张的哲学”Blog.Core项目的代码,个人学习使用,之后会修改掉,如有侵权请联系删除。

 

.netCore下的jwt的梳理-->借鉴于“老张的哲学”

标签:ons   new   class   tco   fss   new t   returns   txt   token   

原文地址:https://www.cnblogs.com/sadsadfd/p/11879440.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!