当前位置:   article > 正文

SpringMVC加JWT token验证_springmvc jwt

springmvc jwt

开发环境:

MyEclipse  2017 CI 10

Spring 5.0

jar文件:

jjwt-0.7.0.jar  ,  jjwt-jackson-0.11.1.jar  ,  jackson-annotations-2.10.0.jar ,jackson-core-2.10.0.jar ,jackson-databind-2.10.0.jar

jar文件下载地址:

https://repo1.maven.org/maven2/com/

jackson-annotations-2.10.0.jar ,jackson-core-2.10.0.jar ,jackson-databind-2.10.0.jar在下列位置

https://repo1.maven.org/maven2/com/fasterxml/jackson/core/

https://download.csdn.net/download/scottfan/12450094

网盘:https://pan.baidu.com/s/1qm-Oiq2ZhlL0YFAdcZBSoQ 

提取码:t3ht

 

在现有SpringMVC项目中新建用于生成Token的package,命名为 com.jwt,然后添加class,这里命名为JwtHelper。

  1. package com.jwt;
  2. import io.jsonwebtoken.*;
  3. import javax.crypto.SecretKey;
  4. import javax.crypto.spec.SecretKeySpec;
  5. import java.util.Date;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. import java.util.UUID;
  9. import org.apache.tomcat.util.codec.binary.Base64;
  10. public class JwtHelper {
  11. private static final String key="scott";
  12. public static String GenerateToken(String userCode) throws Exception
  13. {
  14. String token = "";
  15. String jwt_id = UUID.randomUUID().toString();
  16. token = createJWT(jwt_id,userCode,"",60*120,userCode);
  17. return token;
  18. }
  19. /**
  20. * 解密jwt
  21. *
  22. * @param jwt
  23. * @return
  24. * @throws Exception
  25. */
  26. public static Claims parseJWT(String jwt) throws Exception {
  27. SecretKey key = generalKey(); //签名秘钥,和生成的签名的秘钥一模一样
  28. Claims claims = Jwts.parser() //得到DefaultJwtParser
  29. .setSigningKey(key) //设置签名的秘钥
  30. .parseClaimsJws(jwt).getBody(); //设置需要解析的jwt
  31. return claims;
  32. }
  33. /**
  34. * 创建jwt
  35. * @param id
  36. * @param issuer
  37. * @param subject
  38. * @param ttlMillis
  39. * @return
  40. * @throws Exception
  41. */
  42. private static String createJWT(String id, String issuer, String subject, long ttlMillis,String usercode) throws Exception {
  43. // 指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
  44. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  45. // 生成JWT的时间
  46. long nowMillis = System.currentTimeMillis();
  47. Date now = new Date(nowMillis);
  48. // 创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式的)
  49. Map<String, Object> claims = new HashMap<>();
  50. claims.put("userCode", usercode);
  51. // 生成签名的时候使用的秘钥secret,切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。
  52. // 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
  53. SecretKey key = generalKey();
  54. // 下面就是在为payload添加各种标准声明和私有声明了
  55. JwtBuilder builder = Jwts.builder() // 这里其实就是new一个JwtBuilder,设置jwt的body
  56. .setClaims(claims) // 如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
  57. .setId(id) // 设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
  58. .setIssuedAt(now) // iat: jwt的签发时间
  59. .setIssuer(issuer) // issuer:jwt签发人
  60. .setSubject(subject) // sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志。
  61. .signWith(signatureAlgorithm, key); // 设置签名使用的签名算法和签名使用的秘钥
  62. // 设置过期时间
  63. if (ttlMillis >= 0) {
  64. long expMillis = nowMillis + ttlMillis;
  65. Date exp = new Date(expMillis);
  66. builder.setExpiration(exp);
  67. }
  68. return builder.compact();
  69. }
  70. /**
  71. * 由字符串生成加密key
  72. *
  73. * @return
  74. */
  75. private static SecretKey generalKey() {
  76. // 本地的密码解码
  77. byte[] encodedKey = Base64.decodeBase64(key);
  78. // 根据给定的字节数组使用AES加密算法构造一个密钥
  79. SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
  80. return key;
  81. }
  82. }

 新增针对WebApi方法的拦截器

新增package,命名为com.TokenInterceptor,添加class,命名为ApiInterceptor 并继承于 HandlerInterceptor

  1. package com.TokenInterceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
  6. import org.springframework.web.method.HandlerMethod;
  7. import org.springframework.web.servlet.HandlerInterceptor;
  8. import org.springframework.web.servlet.ModelAndView;
  9. import java.io.PrintWriter;
  10. import java.lang.annotation.ElementType;
  11. import java.lang.annotation.Inherited;
  12. import java.lang.annotation.Retention;
  13. import java.lang.annotation.RetentionPolicy;
  14. import java.lang.annotation.Target;
  15. import java.lang.reflect.Method;
  16. import com.jwt.JwtHelper;
  17. import io.jsonwebtoken.lang.Objects;
  18. public class ApiInterceptor implements HandlerInterceptor {
  19. //JWT工具类
  20. //第一个函数preHandle是预处理函数,比如我们用于拦截登录时,它是第一个工作的。
  21. @Override
  22. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {
  23. //检查请求的地址是否有效,如果不加这个判断,客户端请求地址如果不存在,服务端会有 异常
  24. if (!(handler instanceof HandlerMethod))
  25. {
  26. httpServletResponse.setCharacterEncoding("application/json;charset=UTF-8");
  27. httpServletResponse.setContentType("application/json;charset=UTF-8");
  28. PrintWriter writer = httpServletResponse.getWriter();
  29. StringBuffer jsonTip = new StringBuffer("{\"result\":");
  30. jsonTip.append(false).append(",\"tip\":\"请求的地址无效\"}");
  31. writer.print(jsonTip.toString());
  32. return false;
  33. }
  34. //获取到目标方法对象
  35. HandlerMethod method = (HandlerMethod) handler;
  36. //取到方法上的注解
  37. ExcludeInterceptor methodAnnotation = method.getMethodAnnotation(ExcludeInterceptor.class);
  38. if (methodAnnotation != null) {
  39. //无此注解的一律拦截
  40. System.out.println("This function is restricted");
  41. return false;
  42. }
  43. httpServletResponse.setCharacterEncoding("utf-8");
  44. System.out.println("进入preHandle方法");
  45. //获取我们请求头中的token验证字符
  46. String headerToken=httpServletRequest.getHeader("token");
  47. System.out.println("Token from header:"+headerToken);
  48. String userCode= httpServletRequest.getParameter("userCode");
  49. //getParameter的变量是放在我们请求附带的对象中的字符串,例如post方法中附带的account变量等。
  50. String url = httpServletRequest.getRequestURI();
  51. System.out.println(url);
  52. //检测当前页面,我们设置当页面不是登录页面时对其进行拦截
  53. //if(!httpServletRequest.getRequestURI().contains("login")){
  54. //将token加入返回页面的header
  55. httpServletResponse.setHeader("token",headerToken);
  56. return true;
  57. //当返回true表示第一个阶段结束,随后会执行postHandle和afterCompletion
  58. }
  59. //当请求到达Controller但是未渲染View时进行处理
  60. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  61. }
  62. //相当于最后的回调函数
  63. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  64. }
  65. //拦截器注解
  66. @Target(ElementType.METHOD)
  67. @Retention(RetentionPolicy.RUNTIME)
  68. @Inherited
  69. public @interface ExcludeInterceptor {
  70. }
  71. }

代码中if (!(handler instanceof HandlerMethod))这句必须要加,要不然请求的地址不存在时,服务端会报错

java.lang.ClassCastException:      org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMet

//拦截器注解
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface ExcludeInterceptor {

    }

 这部分代码目的是指定某个方法需要验证Token,拦截器是针对整个Controller中的方法有效的,通过这个拦截器注解,就可以判断出那个方法不用验证。

需要验证Token的方法,加@ExcludeInterceptor注解即可

@ExcludeInterceptor
    @RequestMapping("/PlaceOrder")
    public String PlaceOrder {  
        System.out.println("PlaceOrder");
        return "success";
    }

如登录方法是获取Token的,就不需验证了。具体验证方法,在上述代码块中有标记。

个人学习笔记,部分代码来源于网上代码。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/182344?site
推荐阅读
相关标签
  

闽ICP备14008679号