概述
前后端分离的项目中的用户登录是无状态,也就是无法使用session来记录用户登录状态,可以使用token令牌机制来处理。登录流程
令牌流程
用户提交账户和密码到服务器的认证(登录)接口认证接口 接收账户和密码进行认证认证通过生成token 如果是随机token则需要在服务器进行存储如果是按照特定的协议生成则无需存储 将生成的token响应给前端 前端获取并存储token(cookie、localstorage)当前端再次请求服务器接口时必须携带token(header)概述
当前端再次请求服务器接口时必须携带token(使用header请求头携带token)代码实现
getUserListByPage(){ console.log(document.cookie); var token ; var cookies = document.cookie.split(","); for (let i = 0; i < cookies.length; i++) { var cookie = cookies[i]; var cookieStr = cookie.split("="); if ("token" == cookieStr[0]){ token = cookieStr[1]; } } var _this = this; axios({ method:"get", url:"http://localhost:8080/restful01/user/getUserListByPage", params: { currentPage:_this.pageInfo.currentPage, pageSize:_this.pageInfo.pageSize }, headers:{ "token":token } }).then(function (res) { var data = res.data; console.log(res.data); if (0 == data.code) { // location.href = "test.html"; top.location = "test.html"; } else { _this.tableData = data.t.list; _this.pageInfo.currentPage = data.t.pageNum; _this.pageInfo.pageSize= data.t.pageSize; _this.pageInfo.total = data.t.total; } });}
* IllegalTokenException.java * 自定义异常public class IllegalTokenException extends Exception {
public IllegalTokenException() { } public IllegalTokenException(String message) { super(message); } public IllegalTokenException(String message, Throwable cause) { super(message, cause); } public IllegalTokenException(Throwable cause) { super(cause); } public IllegalTokenException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); }}
* LoginInterceptor.java * 完成token认证 ```java public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if ("options".equalsIgnoreCase(request.getMethod())) { return true; } else { String token = request.getHeader("token"); String username = token.split("-")[0]; String existToken = TokenUtil.getToken(username); if (token.equals(existToken) ) { return true; } else { throw new IllegalTokenException("非法token,请验证!"); } } } } GlobalExceptionResolver.java 全局异常处理期 @ControllerAdvice public class GlobalExceptionResolver { @ResponseBody @ExceptionHandler(IllegalTokenException.class) public ResultVO handleException(Exception e){ return new ResultVO(0,e.getMessage()); } }存在的问题
无法设置token的有效时长开发步骤
引入依赖改造TokenUtil,生成token拦截器校验JWT token改造拦截器LoginInterceptor改造全局异常处理期代码实现
引入依赖 <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.8.3</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency 改造TokenUtil,生成token public class TokenUtil { public static String getToken(User user){ String token = Jwts.builder() .setSubject(user.getUsername()) .setId(user.getId()+"") .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 60 * 1000)) .compact(); return token; }}
* 改造拦截器LoginInterceptor ```java @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws UnTokenException, ExpiredJwtException,SignatureException { if("options".equalsIgnoreCase(request.getMethod())){ return true; }else { String token = request.getHeader("token"); System.out.println(token); if (token != null && !"".equals(token)) { //校验token JwtParser parser = Jwts.parser(); parser.setSigningKey("qianfeng"); //解析token,只要不抛出异常表示token正常 Jws<Claims> claimsJws = parser.parseClaimsJws(token); //从token中获取信息 Claims body = claimsJws.getBody(); String subject = body.getSubject(); return true; } else { throw new UnTokenException("token为NULL"); } } } } 改造全局异常处理期GlobalExceptionResolver @ControllerAdvice public class GlobalExceptionResolver { @ResponseBody @ExceptionHandler(JwtException.class) public ResultVO handleException(Exception e){ return new ResultVO(0,e.getMessage()); } }