当前位置:   article > 正文

springmvc结合jwt的使用,实现前后端分离token验证_springmvc token验证

springmvc token验证

1.首先需要导入maven依赖

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-core</artifactId>
  4. <version>2.9.4</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.fasterxml.jackson.core</groupId>
  8. <artifactId>jackson-databind</artifactId>
  9. <version>2.9.4</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>com.fasterxml.jackson.core</groupId>
  13. <artifactId>jackson-annotations</artifactId>
  14. <version>2.9.4</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>com.alibaba</groupId>
  18. <artifactId>fastjson</artifactId>
  19. <version>1.2.41</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>io.jsonwebtoken</groupId>
  23. <artifactId>jjwt</artifactId>
  24. <version>0.7.0</version>
  25. </dependency>
  26. <dependency>
  27. <groupId>com.auth0</groupId>
  28. <artifactId>java-jwt</artifactId>
  29. <version>3.2.0</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework</groupId>
  33. <artifactId>spring-context</artifactId>
  34. <version>5.1.3.RELEASE</version>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework</groupId>
  38. <artifactId>spring-tx</artifactId>
  39. <version>5.1.3.RELEASE</version>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.quartz-scheduler</groupId>
  43. <artifactId>quartz</artifactId>
  44. <version>2.3.0</version>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.springframework</groupId>
  48. <artifactId>spring-context-support</artifactId>
  49. <version>5.1.3.RELEASE</version>
  50. </dependency>
  51. <dependency>
  52. <groupId>org.springframework</groupId>
  53. <artifactId>spring-test</artifactId>
  54. <version>5.1.3.RELEASE</version>
  55. </dependency>
  56. <dependency>
  57. <groupId>org.springframework</groupId>
  58. <artifactId>spring-web</artifactId>
  59. <version>5.1.3.RELEASE</version>
  60. </dependency>
  61. <dependency>
  62. <groupId>org.springframework</groupId>
  63. <artifactId>spring-webmvc</artifactId>
  64. <version>5.1.3.RELEASE</version>
  65. </dependency>
  66. <dependency>
  67. <groupId>org.slf4j</groupId>
  68. <artifactId>slf4j-log4j12</artifactId>
  69. <version>1.7.16</version>
  70. </dependency>

2.编写jwt工具类

  1. package com.dqw.util;
  2. import java.security.Key;
  3. import java.util.Date;
  4. import javax.crypto.spec.SecretKeySpec;
  5. import javax.xml.bind.DatatypeConverter;
  6. import io.jsonwebtoken.Claims;
  7. import io.jsonwebtoken.JwtBuilder;
  8. import io.jsonwebtoken.Jwts;
  9. import io.jsonwebtoken.SignatureAlgorithm;
  10. /**
  11. * jwt工具类
  12. * @ClassName: JWTUtil
  13. * @Description:TODO
  14. * @author: 丁乾文
  15. * @date: 2019年5月13日 下午7:48:21
  16. */
  17. public class JWTUtil {
  18. /**
  19. * token加密时使用的密钥
  20. * 一旦得到该密钥也就可以伪造token了
  21. */
  22. public static String sercetKey = "InMySchoolOnline";
  23. /**
  24. * 代表token的有效时间
  25. */
  26. public final static long keeptime = 1800000;
  27. /**
  28. * JWT由3个部分组成,分别是 头部Header,载荷Payload一般是用户信息和声明,签证Signature一般是密钥和签名
  29. * 当头部用base64进行编码后一般都会呈现eyJ...形式,而载荷为非强制使用,签证则包含了哈希算法加密后的数据,包括转码后的header,payload和sercetKey
  30. * 而payload又包含几个部分,issuer签发者,subject面向用户,iat签发时间,exp过期时间,aud接收方。
  31. * @Title: generToken
  32. * @Description: TODO
  33. * @param: @param id 用户id
  34. * @param: @param issuer 签发者
  35. * @param: @param subject 一般用户名
  36. * @param: @return
  37. * @return: String
  38. * @throws
  39. */
  40. public static String generToken(String id, String issuer, String subject) {
  41. long ttlMillis = keeptime;
  42. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  43. //使用Hash256算法进行加密
  44. long nowMillis = System.currentTimeMillis();
  45. Date now = new Date(nowMillis);
  46. //获取系统时间以便设置token有效时间
  47. byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(sercetKey);
  48. //将密钥转码为base64形式,再转为字节码
  49. Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
  50. //对其使用Hash256进行加密
  51. JwtBuilder builder = Jwts.builder().setId(id).setIssuedAt(now);
  52. //JWT生成类,此时设置iat,以及根据传入的id设置token
  53. if (subject != null) {
  54. builder.setSubject(subject);
  55. }
  56. if (issuer != null) {
  57. builder.setIssuer(issuer);
  58. }
  59. //由于Payload是非必须加入的,所以这时候要加入检测
  60. builder.signWith(signatureAlgorithm, signingKey);
  61. //进行签名,生成Signature
  62. if (ttlMillis >= 0) {
  63. long expMillis = nowMillis + ttlMillis;
  64. Date exp = new Date(expMillis);
  65. builder.setExpiration(exp);
  66. }
  67. //返回最终的token结果
  68. return builder.compact();
  69. }
  70. /**
  71. * 该函数用于更新token
  72. * @Title: updateToken
  73. * @Description: TODO
  74. * @param: @param token
  75. * @param: @return
  76. * @return: String
  77. * @throws
  78. */
  79. public static String updateToken(String token) {
  80. //Claims就是包含了我们的Payload信息类
  81. Claims claims = verifyToken(token);
  82. String id = claims.getId();
  83. String subject = claims.getSubject();
  84. String issuer = claims.getIssuer();
  85. //生成新的token,根据现在的时间
  86. return generToken(id, issuer, subject);
  87. }
  88. /**
  89. * 将token解密出来,将payload信息包装成Claims类返回
  90. * @Title: verifyToken
  91. * @Description: TODO
  92. * @param: @param token
  93. * @param: @return
  94. * @return: Claims
  95. * @throws
  96. */
  97. private static Claims verifyToken(String token) {
  98. Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(sercetKey))
  99. .parseClaimsJws(token).getBody();
  100. return claims;
  101. }
  102. }

3.编辑token鉴定spring拦截器

  1. package com.dqw.interceptor;
  2. import javax.servlet.http.HttpServletRequest;
  3. import javax.servlet.http.HttpServletResponse;
  4. import org.apache.log4j.Logger;
  5. import org.springframework.web.servlet.HandlerInterceptor;
  6. import org.springframework.web.servlet.ModelAndView;
  7. import com.alibaba.fastjson.JSON;
  8. import com.dqw.util.JWTUtil;
  9. import com.dqw.util.ResponseData;
  10. /**
  11. * token鉴定
  12. * @ClassName: HeaderTokenInterceptor
  13. * @Description:TODO
  14. * @author: 丁乾文
  15. * @date: 2019年5月13日 下午8:52:40
  16. */
  17. public class HeaderTokenInterceptor implements HandlerInterceptor {
  18. private static final Logger LOG = Logger.getLogger(HeaderTokenInterceptor.class);
  19. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
  20. Object handler) throws Exception {
  21. ResponseData responseData = null;
  22. // 获取我们请求头中的token验证字符
  23. String headerToken = httpServletRequest.getHeader("token");
  24. // 检测当前页面,我们设置当页面不是登录页面时对其进行拦截
  25. // 具体方法就是检测URL中有没有login字符串
  26. if (!httpServletRequest.getRequestURI().contains("login")) {
  27. if (headerToken == null) {
  28. // 如果token不存在的话,返回错误信息。
  29. responseData=ResponseData.customerError();
  30. }
  31. try {
  32. // 对token进行更新与验证
  33. headerToken = JWTUtil.updateToken(headerToken);
  34. LOG.debug("token验证通过,并续期了");
  35. } catch (Exception e) {
  36. LOG.debug("token验证出现异常!");
  37. // 当token验证出现异常返回错误信息,token不匹配
  38. responseData=ResponseData.customerError();
  39. }
  40. }
  41. if(responseData!=null) {//如果有错误信息
  42. httpServletResponse.getWriter().write(JSON.toJSONString(responseData));
  43. return false;
  44. }else {
  45. // 将token加入返回页面的header
  46. httpServletResponse.setHeader("token", headerToken);
  47. return true;
  48. }
  49. }
  50. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
  51. ModelAndView modelAndView) throws Exception {
  52. }
  53. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
  54. Object o, Exception e) throws Exception {
  55. }
  56. }

4.项目中用到的其他类

  1. package com.dqw.util;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. /**
  5. * 响应实体
  6. * @ClassName: ResponseData
  7. * @Description:TODO
  8. * @author: 丁乾文
  9. * @date: 2019年5月13日 下午8:53:10
  10. */
  11. public class ResponseData {
  12. private final String message;
  13. private final int code;
  14. private final Map<String, Object> data = new HashMap<String, Object>();
  15. public String getMessage() {
  16. return message;
  17. }
  18. public int getCode() {
  19. return code;
  20. }
  21. public Map<String, Object> getData() {
  22. return data;
  23. }
  24. public ResponseData putDataValue(String key, Object value) {
  25. data.put(key, value);
  26. return this;
  27. }
  28. private ResponseData(int code, String message) {
  29. this.code = code;
  30. this.message = message;
  31. }
  32. public static ResponseData ok() {
  33. return new ResponseData(200, "Ok");
  34. }
  35. public static ResponseData notFound() {
  36. return new ResponseData(404, "Not Found");
  37. }
  38. public static ResponseData badRequest() {
  39. return new ResponseData(400, "Bad Request");
  40. }
  41. public static ResponseData forbidden() {
  42. return new ResponseData(403, "Forbidden");
  43. }
  44. public static ResponseData unauthorized() {
  45. return new ResponseData(401, "unauthorized");
  46. }
  47. public static ResponseData serverInternalError() {
  48. return new ResponseData(500, "Server Internal Error");
  49. }
  50. public static ResponseData customerError() {
  51. return new ResponseData(1001, "customer Error");
  52. }
  53. }
  54. package com.dqw.po;
  55. /**
  56. * 用户实体类
  57. * @ClassName: User
  58. * @Description:TODO
  59. * @author: 丁乾文
  60. * @date: 2019年5月13日 下午8:43:38
  61. */
  62. public class User {
  63. private Integer id;
  64. private String email;
  65. private String password;
  66. public Integer getId() {
  67. return id;
  68. }
  69. public void setId(Integer id) {
  70. this.id = id;
  71. }
  72. public String getEmail() {
  73. return email;
  74. }
  75. public void setEmail(String email) {
  76. this.email = email;
  77. }
  78. public String getPassword() {
  79. return password;
  80. }
  81. public void setPassword(String password) {
  82. this.password = password;
  83. }
  84. package com.dqw.interceptor;
  85. import javax.servlet.http.HttpServletRequest;
  86. import javax.servlet.http.HttpServletResponse;
  87. import org.springframework.web.servlet.HandlerInterceptor;
  88. import org.springframework.web.servlet.ModelAndView;
  89. /**
  90. * 主要解决请求跨域问题
  91. * @ClassName: HttpInterceptor
  92. * @Description:TODO
  93. * @author: 丁乾文
  94. * @date: 2019年5月13日 下午8:46:41
  95. */
  96. public class HttpInterceptor implements HandlerInterceptor {
  97. @Override
  98. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  99. // 允许跨域
  100. response.setHeader("Access-Control-Allow-Origin", "*");
  101. // 允许自定义请求头token(允许head跨域)
  102. response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
  103. return true;
  104. }
  105. @Override
  106. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  107. }
  108. @Override
  109. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  110. }
  111. }
  112. package com.dqw.controller;
  113. import org.springframework.web.bind.annotation.GetMapping;
  114. import org.springframework.web.bind.annotation.RequestMapping;
  115. import org.springframework.web.bind.annotation.RestController;
  116. import com.dqw.util.ResponseData;
  117. /**
  118. * 首页
  119. * @ClassName: IndexController
  120. * @Description:TODO
  121. * @author: 丁乾文
  122. * @date: 2019年5月13日 下午9:09:35
  123. */
  124. @RestController
  125. @RequestMapping("index")
  126. public class IndexController {
  127. @GetMapping("index")
  128. public ResponseData toLogin() {
  129. ResponseData responseData = ResponseData.ok();
  130. return responseData;
  131. }
  132. }
  133. package com.dqw.controller;
  134. import org.springframework.web.bind.annotation.PostMapping;
  135. import org.springframework.web.bind.annotation.RequestMapping;
  136. import org.springframework.web.bind.annotation.ResponseBody;
  137. import org.springframework.web.bind.annotation.RestController;
  138. import com.dqw.po.User;
  139. import com.dqw.util.JWTUtil;
  140. import com.dqw.util.ResponseData;
  141. /**
  142. * @ClassName: LoginController
  143. * @Description:TODO
  144. * @author: 丁乾文
  145. * @date: 2019年5月13日 下午8:41:47
  146. */
  147. @RestController
  148. @RequestMapping("login")
  149. public class LoginController {
  150. /**
  151. * 用户登录
  152. * @Title: login
  153. * @Description: TODO
  154. * @param: @param user
  155. * @param: @return
  156. * @return: ResponseData
  157. * @throws
  158. */
  159. @PostMapping(value="login")
  160. public @ResponseBody ResponseData login(User user) {
  161. //模拟去查询数据库,看是否存在此用户
  162. boolean login = toLogin(user);
  163. ResponseData responseData = ResponseData.ok();
  164. if(login) {
  165. //生成token
  166. String token = JWTUtil.generToken("1", "Jersey-Security-Basic", user.getEmail());
  167. //向浏览器返回token,客户端受到此token后存入cookie中,或者h5的本地存储中
  168. responseData.putDataValue("token", token);
  169. //以及用户
  170. responseData.putDataValue("user", user);
  171. }else {
  172. //用户或者密码错误
  173. responseData=ResponseData.customerError();
  174. }
  175. return responseData;
  176. }
  177. public boolean toLogin(User user) {
  178. if(user.getEmail()!=null&&user.getEmail().trim().length()>0) {
  179. if(user.getEmail().equals("root")) {
  180. if(user.getPassword().equals("123456")) {
  181. return true;
  182. }
  183. }
  184. }
  185. return false;
  186. }
  187. }
  188. }

5.附springmvc配置文件

  1. <context:component-scan base-package="com"></context:component-scan>
  2. <!-- 启动注解驱动 -->
  3. <mvc:annotation-driven/>
  4. <context:annotation-config></context:annotation-config>
  5. <mvc:interceptors>
  6. <!-- 允许跨域 -->
  7. <mvc:interceptor>
  8. <mvc:mapping path="/**"/>
  9. <bean class="com.dqw.interceptor.HttpInterceptor"></bean>
  10. </mvc:interceptor>
  11. <!-- 检验Token -->
  12. <mvc:interceptor>
  13. <mvc:mapping path="/**"/>
  14. <bean class="com.dqw.interceptor.HeaderTokenInterceptor"></bean>
  15. </mvc:interceptor>
  16. </mvc:interceptors>

6.login.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Insert title here</title>
  6. <script type="text/javascript" src="jquery.min.js"></script>
  7. <script type="text/javascript" src="jquery.cookie.js"></script>
  8. </head>
  9. <body>
  10. 邮箱:<input type="text" name="email"><br>
  11. 密码:<input type="text" name="password"><br>
  12. <input type="submit" onclick="signIn()" value="登录">
  13. <script type="text/javascript">
  14. /**
  15. * 登录ajax,登录成功后获取后台返回的token,并把token保存到cookie中
  16. * 以后用户每次请求后台数据需要携带此token
  17. */
  18. function signIn() {
  19. let email = $("input[name='email']").val();
  20. let password = $("input[name='password']").val();
  21. $.ajax({
  22. url: "http://localhost:8080/jwt/login/login.action",
  23. type: "POST",
  24. dataType: "json",
  25. data: {email: email, password: password},
  26. success: function (result) {
  27. if(result.code==200){
  28. //保存token用来判断用户是否登录,和身份是否属实
  29. $.cookie('token', result.data.token);
  30. //$.cookie('user', result.data.user);
  31. //转向主页面
  32. location="index.html";
  33. }else{
  34. alert("用户名或者密码错误!");
  35. }
  36. }
  37. })
  38. }
  39. </script>
  40. </body>
  41. </html>

7.index.html

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>欢迎</title>
  6. <script type="text/javascript" src="jquery.min.js"></script>
  7. <script type="text/javascript" src="jquery.cookie.js"></script>
  8. </head>
  9. <body>
  10. 欢迎你(可以从本地存取获取cookie中获取)
  11. <br>
  12. <button onclick="logout()">注销</button>
  13. <script type="text/javascript">
  14. /**
  15. * 请求数据的ajax,需要从cookie读取token放入head传给后台。
  16. */
  17. loadDeptTree();
  18. function loadDeptTree() {
  19. $.ajax({
  20. // 自定义的headers字段,会出现option请求,在GET请求之前,后台要记得做检验。
  21. headers: {
  22. token: $.cookie('token')
  23. },
  24. url: "http://localhost:8080/jwt/index/index.action",
  25. type: 'GET',
  26. dataType: 'json',
  27. success : function (result) {
  28. if(result.code==200){
  29. alert("加载到的数据:"+result+",并进行渲染页面.....");
  30. }else{
  31. alert("异常,非法token,这里不直接判断是否token不对,实际开发需要各种判断返回码。");
  32. }
  33. }
  34. })
  35. }
  36. /**
  37. * 注销,清空所有cookie(或者只清空保存着token的Cookie就行)
  38. */
  39. function logout() {
  40. var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
  41. if(keys) {
  42. for(var i = keys.length; i--;)
  43. document.cookie = keys[i] + '=0;expires=' + new Date(0).toUTCString()
  44. }
  45. //返回登录页面或者主页
  46. window.location.href = "login.html";
  47. }
  48. </script>
  49. </body>
  50. </html>

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号