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("-", "");
例如:代码片段
代码语言:javascript复制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();
}
}