文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

让JWT来保护你的接口服务

2024-12-03 00:26

关注

大家好,我是大尧。

以前写过一篇关于接口服务规范的文章,原文在此,里面关于安全性问题重点讲述了通过appid,appkey,timestamp,nonce以及sign来获取token,使用token来保障接口服务的安全。今天我们来讲述一种更加便捷的方式,使用jwt来生成token。

一、JWT是什么

JSON Web Token(JWT) 定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT可以设置有效期。

JWT是一个很长的字符串,包含了Header,Playload和Signature三部分内容,中间用.进行分隔。

Headers

Headers部分描述的是JWT的基本信息,一般会包含签名算法和令牌类型,数据如下:

  1.     "alg""RS256"
  2.     "typ""JWT" 

Playload

Playload就是存放有效信息的地方,JWT规定了以下7个字段,建议但不强制使用:

  1. iss: jwt签发者 
  2. sub: jwt所面向的用户 
  3. aud: 接收jwt的一方 
  4. exp: jwt的过期时间,这个过期时间必须要大于签发时间 
  5. nbf: 定义在什么时间之前,该jwt都是不可用的 
  6. iat: jwt的签发时间 
  7. jti: jwt的唯一身份标识,主要用来作为一次性token 

除此之外,我们还可以自定义内容

  1.     "name":"Java旅途"
  2.     "age":18 

Signature

Signature是将JWT的前面两部分进行加密后的字符串,将Headers和Playload进行base64编码后使用Headers中规定的加密算法和密钥进行加密,得到JWT的第三部分。

二、JWT生成和解析token

在应用服务中引入JWT的依赖

  1.  
  2.     io.jsonwebtoken 
  3.     jjwt 
  4.     0.9.0 
  5.  

 

根据JWT的定义生成一个使用RSA算法加密的,有效期为30分钟的token

  1. public static String createToken(User user) throws Exception{ 
  2.  
  3.     return Jwts.builder() 
  4.         .claim("name",user.getName()) 
  5.         .claim("age",user.getAge()) 
  6.         // rsa加密 
  7.         .signWith(SignatureAlgorithm.RS256, RsaUtil.getPrivateKey(PRIVATE_KEY)) 
  8.         // 有效期30分钟 
  9.         .setExpiration(DateTime.now().plusSeconds(30 * 60).toDate()) 
  10.         .compact(); 

登录接口验证通过后,调用JWT生成带有用户标识的token响应给用户,在接下来的请求中,头部携带token进行验签,验签通过后,正常访问应用服务。

  1. public static Claims parseToken(String token) throws Exception{ 
  2.     return Jwts 
  3.         .parser() 
  4.         .setSigningKey(RsaUtil.getPublicKey(PUBLIC_KEY)) 
  5.         .parseClaimsJws(token) 
  6.         .getBody(); 

三、token续签问题

上面讲述了关于JWT验证的过程,现在我们考虑这样一个问题,客户端携带token访问下单接口,token验签通过,客户端下单成功,返回下单结果,然后客户端带着token调用支付接口进行支付,验签的时候发现token失效了,这时候应该怎么办?只能告诉用户token失效,然后让用户重新登录获取token?这种体验是非常不好的,oauth2在这方面做的比较好,除了签发token,还会签发refresh_token,当token过期后,会去调用refresh_token重新获取token,如果refresh_token也过期了,那么再提示用户去登录。现在我们模拟oauth2的实现方式来完成JWT的refresh_token。

思路大概就是用户登录成功后,签发token的同时,生成一个加密串作为refresh_token,refresh_token存放在redis中,设置合理的过期时间(一般会将refresh_token的过期时间设置的比较久一点)。然后将token和refresh_token响应给客户端。伪代码如下:

  1. @PostMapping("getToken"
  2. public ResultBean getToken(@RequestBody LoingUser user){ 
  3.  
  4.     ResultBean resultBean = new ResultBean(); 
  5.     // 用户信息校验失败,响应错误 
  6.     if(!user){ 
  7.         resultBean.fillCode(401,"账户密码不正确"); 
  8.         return resultBean; 
  9.     } 
  10.     String token = null
  11.     String refresh_token = null
  12.     try { 
  13.         // jwt 生成的token 
  14.         token = JwtUtil.createToken(user); 
  15.         // 刷新token 
  16.         refresh_token = Md5Utils.hash(System.currentTimeMillis()+""); 
  17.         // refresh_token过期时间为24小时 
  18.         redisUtils.set("refresh_token:"+refresh_token,token,30*24*60*60); 
  19.     } catch (Exception e) { 
  20.         e.printStackTrace(); 
  21.     } 
  22.  
  23.     Map map = new HashMap<>(); 
  24.     map.put("access_token",token); 
  25.     map.put("refresh_token",refresh_token); 
  26.     map.put("expires_in",2*60*60); 
  27.     resultBean.fillInfo(map); 
  28.     return resultBean; 

客户端调用接口时,在请求头中携带token,在拦截器中拦截请求,验证token的有效性,如果验证token失败,则去redis中判断是否是refresh_token的请求,如果refresh_token验证也失败,则给客户端响应鉴权异常,提示客户端重新登录,伪代码如下:

  1. HttpHeaders headers = request.getHeaders(); 
  2. // 请求头中获取令牌 
  3. String token = headers.getFirst("Authorization"); 
  4. // 判断请求头中是否有令牌 
  5. if (StringUtils.isEmpty(token)) { 
  6.     resultBean.fillCode(401,"鉴权失败,请携带有效token"); 
  7.     return resultBean; 
  8. if(!token.contains("Bearer")){ 
  9.     resultBean.fillCode(401,"鉴权失败,请携带有效token"); 
  10.     return resultBean; 
  11.  
  12. token = token.replace("Bearer ",""); 
  13. // 如果请求头中有令牌则解析令牌 
  14. try { 
  15.     Claims claims = TokenUtil.parseToken(token).getBody(); 
  16. } catch (Exception e) { 
  17.     e.printStackTrace(); 
  18.     String refreshToken = redisUtils.get("refresh_token:" + token)+""
  19.     if(StringUtils.isBlank(refreshToken) || "null".equals(refreshToken)){ 
  20.         resultBean.fillCode(403,"refresh_token已过期,请重新获取token"); 
  21.         return resultbean; 
  22.     } 

refresh_token来换取token的伪代码如下:

  1. @PostMapping("refreshToken"
  2. public Result refreshToken(String token){ 
  3.  
  4.     ResultBean resultBean = new ResultBean(); 
  5.     String refreshToken = redisUtils.get(TokenConstants.REFRESHTOKEN + token)+""
  6.     String access_token = null
  7.     try { 
  8.         Claims claims = JwtUtil.parseToken(refreshToken); 
  9.         String username = claims.get("username")+""
  10.         String password = claims.get("password")+""
  11.         LoginUser loginUser = new LoginUser(); 
  12.         loginUser.setUsername(username); 
  13.         loginUser.setPassword(password); 
  14.         access_token = JwtUtil.createToken(loginUser); 
  15.     } catch (Exception e) { 
  16.         e.printStackTrace(); 
  17.     } 
  18.     Map map = new HashMap<>(); 
  19.     map.put("access_token",access_token); 
  20.     map.put("refresh_token",token); 
  21.     map.put("expires_in",30*60); 
  22.     resultBean.fillInfo(map); 
  23.     return resultBean; 

通过上面的分析,我们简单的实现了token的签发,验签以及续签问题,JWT作为一个轻量级的鉴权框架,使用起来非常方便,但是也会存在一些问题,

下面这段是我网上看到的一段关于JWT比较适用的场景:

比如,用户注册后发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户,一次性的。这种场景就适合使用JWT。

本文转载自微信公众号「Java旅途」,可以通过以下二维码关注。转载本文请联系Java旅途公众号。

 

来源:Java旅途内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯