分布式应用下登录检验解决方案JWT

简介:分布式应用的登录检验解决方案 JWT讲解 json web token

  • 什么是JWT

    • JWT 是一个开放标准,它定义了一种用于简洁,自包含的用于通信双方之间以 JSON 对象的形式安全传递信息的方法。 可以使用 HMAC 算法或者是 RSA 的公钥密钥对进行签名
    • 简单来说: 就是通过一定规范来生成token,然后可以通过解密算法逆向解密token,这样就可以获取用户信息
          	  {
                    id:888,
                    name:'小D',
                    expire:10000
                }
                
                funtion 加密(object, appsecret){
                    xxxx
                    return base64( token);
                }
    
                function 解密(token ,appsecret){
    
                    xxxx
                    //成功返回true,失败返回false
                }
    
    • 优点

      • 生产的token可以包含基本信息,比如id、用户昵称、头像等信息,避免再次查库
      • 存储在客户端,不占用服务端的内存资源
    • 缺点

      • token是经过base64编码,所以可以解码,因此token加密前的对象不应该包含敏感信息,如用户权限,密码等

      • 如果没有服务端存储,则不能做登录失效处理,除非服务端改秘钥

  • JWT格式组成 头部、负载、签名

    • header+payload+signature
      • 头部:主要是描述签名算法
      • 负载:主要描述是加密对象的信息,如用户的id等,也可以加些规范里面的东西,如iss签发者,exp 过期时间,sub 面向的用户
      • 签名:主要是把前面两部分进行加密,防止别人拿到token进行base解密后篡改token
  • 关于jwt客户端存储

    • 可以存储在cookie,localstorage和sessionStorage里面
第7集 登录校验Json Web Token实战之封装通用方法

讲解:引入相关依赖并开发JWT工具类, 开发生产token和校验token的办法

  • 聚合工程加入版本依赖,common项目加入相关依赖

        <!-- JWT相关 -->
        <dependency>
          <groupId>io.jsonwebtoken</groupId>
          <artifactId>jjwt</artifactId>
          <version>0.7.0</version>
        </dependency>
    
  • common项目中封装生产token方法

         /**
         * 根据用户信息,生成令牌
         *
         * @param user
         * @return
         */
        public static String geneJsonWebToken(LoginUser user) {
    
            Long userId = user.getId();
            String token = Jwts.builder().setSubject(SUBJECT)
                    .claim("head_img", user.getHeadImg())
                    .claim("id", userId)
                    .claim("name", user.getName())
                    .claim("mail", user.getMail())
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                    .signWith(SignatureAlgorithm.HS256, SECRET).compact();
    
            token = TOKEN_PREFIX + token;
    
            return token;
        }
    
  • 封装校验token方法

     /**
         * 校验token的方法
         *
         * @param token
         * @return
         */
        public static Claims checkJWT(String token) {
    
            try {
    
                final Claims claims = Jwts.parser().setSigningKey(SECRET)
                        .parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
    
                return claims;
    
            } catch (Exception e) {
                return null;
            }
    
        }
    
    
第8集 【加餐扩展】JWT登录过期-自动刷新token方案介绍

讲解:JWT过期自动刷新方案介绍

  • 背景
在前后分离场景下,越来越多的项目使用jwt token作为接口的安全机制,但存在jwt过期后,用户无法直接感知,假如在用户操作页面期间,突然提示登录,则体验很不友好,所以就有了token自动刷新需求

但是这个自动刷新方案,基本都离不开服务端状态存储,JWT推出思想是:去中心化,无状态化,所以有所违背

类似这样的业务,有阿里云首页,没有做token刷新令牌维护,但是符合对应的思想
  • 方案:前端控制检测token,无感知刷新 (推荐)
用户登录成功的时候,一次性给他两个Token,分别为AccessToken和RefreshToken
AccessToken有效期较短,比如1天或者5天,用于正常请求
RefreshToken有效期可以设置长一些,例如10天、20天,作为刷新AccessToken的凭证

刷新方案:当AccessToken即将过期的时候,例如提前30分钟,客户端利用RefreshToken请求指定的API获取新的AccessToken并更新本地存储中的AccessToken

核心逻辑
1、登录成功后,jwt生成AccessToken; UUID生成RefreshToken并存储在服务端redis中,设置过期时间
2、接口返回3个字段AccessToken/RefreshToken/访问令牌过期时间戳
3、由于RefreshToken存储在服务端redis中,假如这个RefreshToken也过期,则提示重新登录; 


老王的疑问:RefreshToken有效期那么长,和直接将AccessToken的有效期延长有什么区别

答:RefreshToken不像AccessToken那样在大多数请求中都被使用,主要是本地检测accessToken快过期的时候才使用,
一般本地存储的时候,也不叫refreshToken,前端可以取个别名,混淆代码让攻击者不能直接识别这个就是刷新令牌


缺点:前端每次请求需要判断token距离过期时间
优点:后端压力小,代码逻辑改动不大
  • 方案二:后端存储判断过期时间
后端存储AccessToken,每次请求过来都判断是否要过期,如果快要过期则重新生成新的token,并返回给前端重新存储,比如距离1天就过期的情况,如果用户访问对应的接口则会更新,但假如没访问则token已经过期则需要重新登录


优点:前端改动小,只需要存储响应http头里面是否有新的令牌产生,有的话就重新存储
缺点:后端实现复杂,且泄露后容易存在一直保活状态,且前端会存在并发请求,当并发请求收到多个jwt token时,容易生成多个token混乱使用
第9集 【加餐扩展】JWT令牌token泄露恶意使用-解决方案

讲解:JWT令牌泄露解决方案-避免盗用后被恶意使用

  • 解密:使用互联网大厂的产品时经常遇到这个情况

    • 比如阿里云或者淘宝,你现在登录了然后换个网络或者地域就需要重新登录
    • 就是对应的token令牌,不只简单的算法加密,还包括了客户端属性、地理网络位置信息等,一起组成一个token令牌
  • 如何避免token令牌泄露被恶意使用

    • ip绑定方式
    生成token的时候,加密的payload加入当前用户ip。
    
    拦截器解密后,获取payload的ip和当前访问ip判断是否同个,如果不是则提示重新登录
    
    优点:服务端无需存储相关内容,性能高,假如用户广州登录,泄露了token给杭州的黑客,依旧用不了
    
    缺点:如果用户用使用过程中ip变动频繁,则操作会经常提示重新登录,体验不友好
    
    当然也可以让用户开启安全模式和非安全模式,让用户自己知道这个情况,一些区块链、比特币交易所里面就会让用户自己选择控制这个token令牌安全是否和ip、终端、地理网络信息进行绑定
    
    					{
                    id:888,
                    name:'小D',
                    ip:“128.23.12.31”
                    expire:10000
                }
                
                funtion 加密(object, appsecret){
                    xxxx
                    return base64( token);
                }
    
                function 解密(token ,appsecret){
    					
                    xxxx
                    //成功返回true,失败返回false
                }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITzhongzi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值