首页 > 编程知识 正文

jwt防止token泄露,jwttoken过期自动续期解决方案

时间:2023-05-06 11:45:09 阅读:207991 作者:2334

文章目录 1. 两种token认证方式2. jwt的token加密解密过程3. token登出、改密后失效4. token的自动续期、一定时间内无操作掉线

1. 两种token认证方式

传统的token认证

用户登录,服务端给前端返回token,并将token保存在服务端。
以后用户再来访问时,需要携带token,服务端获取token后再去数据库获取token做校验。

JWT的token认证

用户登录,服务端给用户返回一个token(服务端不保存)
以后用户再来访问时,需要携带token,服务端获取token做校验

两种认证方式对比:
jwt相对于传统的token认证,无需将token保存在服务端。


2. jwt的token加密解密过程

2.1 生成token

用户登录成功后,使用jwt创建一个token,并返回给用户,token格式如下

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 //第一段.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ //第二段.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c //第三段

注意:jwt生成的token是由三段字符串拼接而成,使用 . 连接起来

①:token的第一段字符串:由下面的json数据通过base64(可逆)加密算法得到。 { "alg": "HS256", //第三段字符串的不可逆加密类型HS256 "typ": "JWT" //token类型JWT} ② token的第二段字符串:是由下面的payload信息通过base64(可逆)加密算法得到 // payload信息 为自定义值,一般不放敏感信息{ "sub": "1234567890", //用户id "name": "John Doe",//用户名 "exp": 1516239022//token过期时间} ③:token的第三段字符串构成:
1.先将第一段和第二段的密文拼接起来
2.对拼接起来的密文字符串和自定义的盐进行 上边指定的HS256加密
3.对HS256加密后的密文再做base64加密

注意:第一、二部分可以通过Base64解密得到,但第三部分不可以!

生成token代码如下

/** * 生成token * @return token * @Param 对象map结构 */ public static String generateToken(Map<String,Object> param){ Date date = new Date(); Date expireTime = new Date(date.getTime() + expire * 1000); String token = Jwts.builder() .setHeaderParam("typ", "JWT") .setClaims(param)//数据// .setSubject(userId + "") .setIssuedAt(date) .setExpiration(expireTime)//过期时间 .signWith(SignatureAlgorithm.HS256, secret) //秘钥 .compact(); return token; }


2.2 验证(解密)token

当用户再来访问时,需要携带token,后端需要对token进行校验

①:获取token②:对token进行切割成三部分③:对第二段字符串进行base64解密,检测token是否超时?④:对第一二段字符串拼接,再次进行HS256加密,得到密文字符串⑤:对token的第三段HS256加密

解密验证代码:

/** * 验证token * @return token正确返回对象,token不正确返回null */ public static Claims getClaimByToken(String token){ try { return Jwts.parser() .setSigningKey(secret) //获取秘钥 .parseClaimsJws(token)//解析验证token .getBody(); }catch (Exception e){ log.info("token验证失败",e); return null; } }

ps : token一旦生成,在过期时间内永久有效,即使项目重启!想要失效token必须等待过期,或者重置盐值!
          
          

3. token登出、改密后失效

使用jwt时,一般修改密码或退出登录时,需要把正在使用的token做失效处理,防止别的客户端使用失效token访问信息。

方案一:在每次修改密码或者退出登录后,修改一下自定义的盐值。当进行下次访问时,会根据自定义盐值验证token,修改了自定义盐值,自然访问不通过。方案二:利用数据库,存放一个修改或者登出的时间,在创建token时,标注上创建时间。如果这个创建时间小于修改或登出的时间,就表示它是修改或者登出之前的token,为过期token /** * 生成jwt token */ public String generateToken(String userId,Boolean rememberMe) { Date nowDate = new Date(); long expiration = rememberMe ? expireRemember : expire; //过期时间 Date expireDate = new Date(nowDate.getTime() + expiration * 1000); System.out.println("登录过期时间 >>>>"+DateUtils.formatDateTime(expireDate)); return Jwts //创建一个JwtBuilder对象 .builder() //设置头信息 .setHeaderParam("typ", "JWT") //设置主题信息 .setSubject(userId) .setIssuedAt(nowDate)//创建时间 .setExpiration(expireDate)//过期时间 //签名手段,参数1:算法,参数2:盐 .signWith(SignatureAlgorithm.HS256, secret) //获取token .compact(); } /** * token是否过期 * @return true:过期 * lastLoginDate 数据库记录的最后一次登出时间 * issueDate token 创建时间 */ public boolean isTokenExpired(Date expiration,Date lastLoginDate,Date issueDate) { //token创建时间小于数据库记录的最后一次登出时间 过期 if(lastLoginDate == null){ return expiration.before(new Date()); }else{ return issueDate.before(lastLoginDate); } }

拦截器的判断:

if(jwtUtils.isTokenExpired(claims.getExpiration(),user.getLoginDate(),claims.getIssuedAt())){ Result result = ResultGenerator.genFailResult(ResultCode.UNAUTHORIZED,"token失效,请重新登录"); SendMsgUtil.sendJsonMessage(response,result); return false; }

          
          

4. token的自动续期、一定时间内无操作掉线

场景:用户登陆后,token的过期时间为30分钟,如果在这30分钟内没有操作,则重新登录,如果30分钟内有操作,就给token自动续一个新的时间。避免用户正在操作时掉线重登!
          

实现①:在jwt生成token时先不设置过期时间,过期时间的操作放在redis中。

①:在登陆时,把用户信息(或者token)放进redis,并设置过期时间

②:如果30分钟内用户有操作,前端带着token来访问,过滤器解析token得到用户信息,去redis中验证用户信息,验证成功则在redis中增加过期时间,验证失败,返回token错误。实现了token时间的自动更新。

③:如果30分钟内用户无操作,redis中的用户信息已过期,此时再进行操作,token解析出的用户信息在redis中验证失败,则重新登录。实现了一定时间内无操作掉线!

实现②:使用access_token、refresh_token 解决

登录获取token(包括访问令牌access_token,刷新令牌refresh_token),其中access_token设置过期时间为5分钟,refresh_token设置过期时间为30分钟。不能同时过期前端保存access_token和refresh_token,每次请求带着access_token去访问服务器资源服务器校验access_token有效性,通过解析access_token看是否能解析出用户信息。如果用户信息为null,说明token无效,返回401,让用户重新登录服务器端校验access_token是否过期 如果access_token没有过期,则token正常,继续执行业务逻辑如果access_token过期,计算 过期后到当前的时间大小 是否在refresh_token过期时间之内(是否大于30 - 5 - 5 = 20分钟,为什么不是30 - 5 = 25分钟呢?主要是想对正在请求的用户token做一个缓存,保证在最后五分钟内,新、老token都有效!防止正在进行的请求token突然失效!), 如果大于refresh_token的过期时间,则表示用户长时间无操作,token真正过期了,返回401,让用户重新登录如果小于refresh_token的过期时间,则继续让该access_token访问业务,但返回给前端标识,提示token已过期,让前端带着refresh_token去服务器获取新的access_token,并保存在前端,后续使用新的access_token去访问!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。