首页 > 其他分享 >JWT

JWT

时间:2022-12-28 09:22:39浏览次数:51  
标签:JWT jwt Token token new public

微服务系列之授权认证(三) JWT

 

1.JWT简介

  官方定义:JWT是JSON Web Token的缩写,JSON Web Token是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,可以将各方之间的信息作为JSON对象安全地传输。该信息可以被验证和信任,因为它是经过加密的。

  实际上,Oauth2.0中的access token一般就是jwt格式。

  token由三部分组成,通过"."分隔,分别是:

      ● 标头

      ● 有效载荷

      ● 签名

  所以JWT表示为:aaaaa.bbbbb.ccccc组成。

  1)标头,Header通常由两部分组成:使用的加密算法 "alg" 以及Token的种类 "typ"。如下:

  

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

  此JSON被Base64Url编码以形成JWT的第一部分。

  2)有效荷载,Payload主要包含了声明Claims,声明实际就是key:value数据,主要包含以下三种声明:

  Registered Claims: 注册声明,为IANA JSON Web Token 注册表中预先定义好的声明,这些声明非强制性,但是建议使用,如

  • ●  iss(issuer):签发人

    ●  exp(expiration time) :过期时间

    ●  sub(subject):主题

    ●  aud(audience):受众

    ●  nbf(not befaore):生效时间

    ●  lat(issued at):签发时间

    ●  jti(jwt id):编号

  Public Claims:公共声明,名称可以被任意定义。为了防止重复,任何新的Claim名称都应该被定义在IANA JSON Web Token Registry中或者使用一个包含不易重复命名空间的URI。

  Private Claims:私有声明,是在团队中约定使用的自定义Claims,既不属于Registered也不属于Public。

  此JSON进行Base64Url编码形成JWT的第二部分

  3)Signature,签名是将第一部分(header)、第二部分(payload)、密钥(key)通过指定算法(HMAC、RSA)进行加密生成的。

  

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

生成的签名就是JWT的第三部分。

将这三部分拼接在一起并使用"."分隔后形成的字符串就是Token。如:

可以使用jwt.io的Debugger解码,验证或生成JWT。

 

注意:虽然签名过后的Token可以防止篡改,但是Token的信息是公开的,任何人都可以读取,所以尽量不要在有效载荷或标头传递敏感信息(如密码)。

2.使用场景

1)目前来说,几乎所有之前使用cookie,session的地方,都可以换成jwt。

2)标准的对C或者对B的微服务系统,这个和之前讲的Oauth2.0协议最大的不同之处,jwt只是一个传输令牌,oauth2.0是一个授权协议,jwt可以理解为是oauth2.0的一部分。。。

3)信息安全交换,由于签名防篡改机制,可以验证其发行人和收件人。

3.Jwt的优势

1)无需存储,无服务器压力,轻量级使用,简单上手。

2)无视跨域,可多端使用,不像cookie、session依赖浏览器。

4.前端滑动登录状态管理方案

jwt token的过期时间如果短了,很影响前端用户操作体验,所以一般情况都是中长期的,以前的session管理登录状态,是滑动的,而现在jwt是无状态的,那么怎么才能做到滑动管理呢,具体细节分析请看这篇文章.NET Core WebAPI 认证授权之JWT(四):JWT续期问题 - 不落阁 (leo96.com) ,虽然没有解决,但是问题抛出的很细致,,我来说说我们现在正在使用的方案。

其实也很简单,用户请求后端服务数据时,作为有效动作,并且触发2小时的计时器,没到2小时的定时器清除并且重新启动,如果2小时内用户没有任何动作,认为是可以退出登录。

5..net core使用jwt

nuget安装System.IdentityModel.Tokens.Jwt

新建一个service写一个生成token的方法

复制代码
 public class TokenService : ITokenService
    {
        private IConfiguration configuration;

        public TokenService(IConfiguration configuration)
        {
            this.configuration = configuration;
        }

        public async Task<string> MakeJwtToken(long userId)
        {
            var claims = new[]
                {
                 // 角色需要在这里填写
         new Claim(ClaimTypes.Role, "Admin"),
         // 多个角色可以重复写,生成的 JWT 会是一个数组
                  new Claim(ClaimTypes.Role, "SuperAdmin"),
                  //其他声明
                  new Claim("uid", userId.ToString())
                };
            //私钥,验证方也需要使用这个进行验证。
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Auth:SecurityKey"]));
            //加密方式
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: "AESCR",//发行人
                audience: "AESCR",//接收人
                claims: claims,
                expires: DateTime.Now.AddMonths(30),//过期时间
                signingCredentials: creds);
            var res = new JwtSecurityTokenHandler().WriteToken(token);
            return await Task.FromResult<string>(res);
        }
    }
复制代码

启动类认证注入

复制代码
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options => {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,//是否验证发行人
                        ValidateAudience = true,//是否验证收件人
                        ValidateLifetime = true,//是否验证失效时间
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidAudience = "AESCR",//Audience
                        ValidIssuer = "AESCR",//Issuer,这两项和后面签发jwt的设置一致
                        ClockSkew = TimeSpan.Zero, // // 默认允许 300s  的时间偏移量,设置为0
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Auth:SecurityKey"]))//与创建者密钥一致
                    };
                });
复制代码
  app.UseAuthentication();//添加认证中间件

控制器代码

复制代码
/// <summary>
        /// 编辑用户信息
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        [HttpPost("{userId}/edit/userInfo")]
        [ProducesResponseType(typeof(Users), (int)HttpStatusCode.OK)]
        [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)]
        [Authorize]//token认证标签,如果需要角色认证,[Authorize(Roles ="admin")]
        public async Task<IActionResult> EditUserInfo([FromRoute] long userId, [FromBody] EditUserInfoCommand command)
        {
            if (!this.CheckUser(command.UserId))
                return BadRequest("您没有权限访问");

            var result = await userService.EditUserInfo(command);
            if (!result.IsSuccess)
                return BadRequest(result.FailureReason);
            return Ok(result.GetData());
        }
复制代码

以上代码就完事了,简单吧,在请求的时候,带上token就可以了。

这里有一个细节问题,由于我们这里用户ID,都是在jwt的Payload中,那么是否还需要请求接口的时候在参数中传输呢?个人理解是这样:

1.首先先看下token验证过后,怎么取claims的声明

复制代码
 public static class ControllerExtensions
    {
        public static long GetUserId(this ControllerBase controllerBase)
        {
            var claim = controllerBase.User.Claims.Where(p => p.Type == "uid").FirstOrDefault();
            if (claim == null)
                return 0;
            long res = 0;
            long.TryParse(claim.Value, out res);
            return res;
        }

        public static bool CheckUser(this ControllerBase controllerBase, long userId)
        {
            return controllerBase.GetUserId() == userId;
        }
    }
复制代码

我可以从payload中获取到创建token时带进去的用户id---uid,回到问题,我认为即使可以拿到用户ID,也需要从接口参数中传递过来,因为安全认证是一个切面拦截,我们的服务如果去掉切面,要保障正常运行,我们只需要在加一个传递参数中的uid和声明里的uid是否一致,来判断是否是当前用户的操作。

标签:JWT,jwt,Token,token,new,public
From: https://www.cnblogs.com/Leo_wl/p/17009416.html

相关文章

  • Token与JWT
    Token与JWT的区别?Token和JWT(JSONWebToken)都是用来在客户端和服务器之间传递身份验证信息的一种方式。但是它们之间有一些区别。Token是一个通用术词,可以指代......
  • JWT(生成Token令牌)
    .NetCore配置使用什么是JWT(详情在面试.md中有)JWT是目前最流行的跨域身份验证解决方案,JWT的原则是在服务器身份验证之后,会返回一个Json数据,,之后,当用户与服务器通信......
  • .net Core 系统 架构回忆录----.net 6+jwt 验证服务
    现在越来越多的项目或多或少会用到JWT,为什么会出现使用JWT这样的场景的呢?假设现在有一个APP,后台是分布式系统。APP的首页模块部署在上海机房的服务器上,子页面模块部署在深......
  • Jwt加密
    importjwt#加密encode_jwt=jwt.encode({'uid':'123'},'123',algorithm='HS256')print(encode_jwt)#解密#强转encode_jwt=str(encode_jwt)decode_jwt=j......
  • Python通过Jwt创建Token
    importtimeimportjwt#pipinstallPyJWTimporthashlibimportjsonimportbase64frompyDesimportdes,PAD_PKCS5,CBCSECRET_KEY='django-insecure-fr&......
  • 彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-JWT和中间件(Middlewar
    前文再续,上一回我们完成了用户的登录逻辑,将之前用户管理模块中添加的用户账号进行账号和密码的校验,过程中使用图形验证码强制进行人机交互,防止账号的密码被暴力破解。本回......
  • JWT(生成Token令牌)
    .NetCore配置使用什么是JWT(详情在面试.md中有)JWT是目前最流行的跨域身份验证解决方案,JWT的原则是在服务器身份验证之后,会返回一个Json数据,,之后,当用户与服务器通信......
  • 别再用 JWT 作为 Session 系统了,问题重重,后果很危险!
    JSONWebTokens,又称JWT。本文将详解:为何JWT不适合存储Session,以及JWT引发的安全隐患。望各位对JWT有更深的理解!十分不幸,我发现越来越多的人开始推荐使用JWT管理......
  • SpringSecurity+JWT认证流程解析
    纸上得来终觉浅,觉知此事要躬行。楔子本文适合:对SpringSecurity有一点了解或者跑过简单demo但是对整体运行流程不明白的同学,对SpringSecurity有兴趣的也可以当作你们......
  • 用户认证:基于jwt和session的区别和优缺点
    用户认证:基于jwt和session的区别和优缺点1.背景知识Authentication和Authorization的区别:Authentication:用户认证,指的是验证用户的身份,例如你希望以小A的身份登录,那么......