Spring Boot 使用 拦截器 实现 token 验证
Spring Boot 使用 拦截器 实现 token 验证
整体思路:
1.写一个工具类封装生成、校验和解析 token 的方法;
2.在注册和登录时生成 token ,生成的 token 存入 redis ,下次登录去 redis 获取,如果存在则直接返回通过
3.在拦截器中校验和解析 token ,拿到 token 中有用的信息存入 private static final InheritableThreadLocal<UserDto> *THREAD_LOCAL* = new InheritableThreadLocal<>(); ,以便后续取用。
实现
1.过滤器
2.网关,spring zuul 经过网关:对登录的权限做限制。
1.JWT方案,可以将登录后的数据加密后通过请求头传输,在接收端接口中可以直接解析来使用。比如:用户ID,用户名称。更多的使用于不可变化的参数。
2.Authorization: 手机号+UUID方案,目前平台都是通过手机号作为账号,附加UUID,作为请求头发起请求,在接收端接口中,根据解析的手机号,通过redis中保存的手机号+UUID是否一致。
验证通过之后,可以通过该手机号查询该手机号的相关信息,比如权限,角色(动态变化的参数),然后保存到InheritableThreadLocal对象中。
String uuid = UUID.randomUUID().toString().replace("-", "");
例如:代码片段
public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取 header 中的 Authorization 信息 String token = request.getHeader("Authorization"); UserHolder.remove(); //对token验证 //验证不通过 throw new BusinessException("0", "没有登录或登录失效,请重新登录"); //全局异常捕获 //验证通过 //封装用户信息 UserHolder.setUserInfo(userLoginInfo); return true; } //全局异常捕获 package com.example.core.mydemo.java; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @Slf4j @ControllerAdvice public class GlobalExceptionAdvisor { /** * 系统异常 * @param e * @return */ @ResponseBody @ExceptionHandler(Exception.class) public ResponseData handleException(Exception e){ log.error("GlobalExceptionAdvisor.handleException",e); ResponseData responseData = new ResponseData("code","msg"); return responseData; } /** * 业务异常 * @param e * @return */ @ResponseBody @ExceptionHandler(BusinessException.class) public ResponseData handleBusinessException(BusinessException e){ log.error("GlobalExceptionAdvisor.handleOrderException",e); ResponseData responseData = new ResponseData(e.getResCode(),e.getMessage()); return responseData; } } public class ResponseData<T> { private static final long serialVersionUID = 6898451165550538312L; @AutoDocProperty(value = "返回代码") private String resCode; @AutoDocProperty(value = "返回消息") private String resMsg; @AutoDocProperty(value = "返回实体") private T data; public ResponseData() { } public ResponseData(String resCode, String resMsg) { this.resCode = resCode; this.resMsg = resMsg; } public String getResCode() { return resCode; } public void setResCode(String resCode) { this.resCode = resCode; } public String getResMsg() { return resMsg; } public void setResMsg(String resMsg) { this.resMsg = resMsg; } public T getData() { return data; } public void setData(T data) { this.data = data; } } package com.example.core.mydemo.java; public class UserLoginInfoVo { private String userId; private String userName; public UserLoginInfoVo() { super(); } public UserLoginInfoVo(String userId, String userName) { this.userId = userId; this.userName = userName; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } } package com.example.core.mydemo.java; import java.util.ArrayList; import java.util.List; /** * 存放用户信息的容器 */ public class UserHolder { private static final InheritableThreadLocal<UserLoginInfoVo> THREAD_LOCAL = new InheritableThreadLocal<UserLoginInfoVo>(){ @Override protected UserLoginInfoVo initialValue() { //初始化对象 UserLoginInfoVo userLoginInfoVo = new UserLoginInfoVo("1","admin"); return userLoginInfoVo; } }; private UserHolder() { } /** * 获取线程中的用户 * @return 用户信息 */ public static UserLoginInfoVo getUserInfo() { return THREAD_LOCAL.get(); } /** * 设置当前线程中的用户 * @param info 用户信息 */ public static void setUserInfo(UserLoginInfoVo info) { THREAD_LOCAL.set(info); } /** * 获取登录的用户的ID * @return */ public static String getUserId() { UserLoginInfoVo dto = THREAD_LOCAL.get(); if (dto != null) { return dto.getUserId(); } else { // 注册或登录时没有,返回 0 return ""; } } public static void remove() { THREAD_LOCAL.remove(); } }