一、自定义拦截器
package com.example.demo.test;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Objects;
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private RedisService redis;
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws IOException {
String tokenName = "Authorization";
// 尝试从header中取token
String token = request.getHeader(tokenName);
//尝试从参数中取token
if (StrUtil.isEmpty(token)) {
token = request.getParameter(tokenName);
}
//尝试从cooke
if (StrUtil.isEmpty(token)) {
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (Objects.equals(cookie.getName(), tokenName)) {
token = cookie.getValue();
}
}
}
//如果前端没有携带token返回json数据
if (StrUtil.isBlank(token)) {
PrintWriter pw = response.getWriter();
pw.write(JSON.toJSONString("用户未登录"));
return false;
}
//解析token
String jwtId = JwtTool.checkJwtToken(token);
if (jwtId == null) {
throw new ServiceException(401, "用户未登录");
}
//获取用户ID
String tokenUserId = JwtTool.getUserId(token);
//token存在,但是redis不存在。要么是失效,要么是强制下线
JwtInfo jwt = redis.get(RedisKey.getToken(tokenUserId, jwtId));
if (jwt == null || !jwt.getToken().equals(token)) {
throw new ServiceException(401, "您当前登录的账号已失效,请重新登录");
}
//获取用户ID
Long userId = jwt.getUserId();
//查询用户
User user = userService.selectById(userId);
//判断用户是否存在
if (user == null) {
throw new ServiceException(MsgCode.CODE_UNAUTHORIZED, "用户不存在");
}
//根据业务需求增加其他判断条件
if (user.getStatus() == 1) {
throw new ServiceException(MsgCode.CODE_UNAUTHORIZED, "用户已禁用!");
}
//将登录用户放到ThreadLocal变量变量中,方便业务获取当前登录用户
CurrentUser currentUser = new CurrentUser();
currentUser.setId(userId);
currentUser.setUserName(user.getAccountname());
currentUser.setNickName(user.getName());
//当前用户放到ThreadLocal变量变量中
CurrentUserUtil.set(currentUser);
return true;
}
}
涉及其他类
public class CurrentUserUtil {
private CurrentUserUtil() {
}
private static final ThreadLocal<CurrentUser> CURRENT_USER = new ThreadLocal<CurrentUser>();
public static void set(CurrentUser currentUser) {
CURRENT_USER.set(currentUser);
}
public static CurrentUser currentUser() {
return CURRENT_USER.get();
}
public static void remove() {
CURRENT_USER.remove();
}
}
package com.example.demo.test;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.List;
/**
* 当前登录用户信息
*/
@Getter
@Setter
public class CurrentUser implements Serializable {
private static final long serialVersionUID = -327159787234887122L;
private Long id;
private String jwtId;
/**
* 当前用户姓名或昵称
*/
private String nickName;
/**
* 当前用户账户
*/
private String userName;
/**
* 当前用户电话
*/
private String phone;
/**
* 当前用户部门ID
*/
private Long deptId;
/**
* 当前用户部门名称
*/
private String deptName;
/**
* 当前用户部门级别 0为中心 1位部门
*/
private Integer level;
/**
* 当前用户是否是部门管理员
*/
private Integer flag;
/**
* 当前用户角色
*/
private List<String> authorityList;
}
package com.example.demo.test;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class JwtInfo implements java.io.Serializable {
/**
* 唯一凭证
*/
private String jwtId;
/**
* 用户ID
*/
private Long userId;
/**
* token
*/
private String token;
}
package com.example.demo.test;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.jwt.JWT;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
public class JwtTool {
/**
* 有效期
**/
private static int expDays = 7;
/**
* 签发者
**/
private static String issuer = "xxxxxx";
/**
* 秘钥
**/
private static String key = "xxxxx";
/**
* 有效载荷
**/
public interface Payload {
String userId = "userId";
String jwtId = "jwtId";
}
/**
* 创建token
*
* @param userId
* @return
*/
public static JwtInfo createJwtToken(Long userId) {
String jwtId = UUID.randomUUID().toString();
try {
String token = JWT.create()
.setIssuer(issuer)
.setIssuedAt(DateTime.now())
.setJWTId(jwtId)
.setCharset(Charset.forName("utf-8"))
//有效载荷
.setPayload(Payload.userId, userId)
.setPayload(Payload.jwtId, jwtId)
.setKey(key.getBytes("utf-8"))
//7天有效期
.setExpiresAt(DateUtil.offsetDay(DateUtil.date(), expDays))
.sign();
JwtInfo jwtInfo = new JwtInfo();
jwtInfo.setUserId(userId);
jwtInfo.setJwtId(jwtId);
jwtInfo.setToken(token);
return jwtInfo;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 验证token
*
* @param token
* @return jwtId
*/
public static String checkJwtToken(String token) {
JWT jwt = JWT.of(token);
//如果验证成功
boolean status;
try {
status = jwt.setKey(key.getBytes("utf-8")).verify();
if (status) {
Object jwtId = jwt.getPayload(Payload.jwtId);
if (jwtId != null) {
return jwtId.toString();
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
/**
* 验证token
*
* @param token
* @return jwtId
*/
public static String getUserId(String token) {
JWT jwt = JWT.of(token);
return jwt.getPayload(Payload.userId).toString();
}
}
package com.example.demo.test;
/**
* 生成RedisKey
*
*/
public interface RedisKey {
/**
* token
*/
String TOKEN = "token:%s:%s";
static String getToken(String id, String jwtId) {
String format = String.format(TOKEN, id,jwtId);
return format;
}
}
package com.example.demo.test;
/**
* 业务逻辑异常
*
*/
public class ServiceException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 5909435651426033878L;
private Integer code;
public ServiceException(String message) {
super(message);
this.code = 201;
}
public ServiceException(Integer code, String message) {
super(message);
this.code = code;
}
public ServiceException(Throwable cause) {
super(cause);
}
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
package com.example.demo.test;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
@Getter
@Setter
public class User implements Serializable {
/**
* 用户id
*/
private Long id;
/**
* 姓名
*/
private String name;
/**
* 密码
*/
@JsonIgnore
private String password;
/**
* 账户
*/
private String userName;
private Date createTime;
}
二、将拦截器加入系统拦截器
package com.example.demo.config;
import com.example.demo.test.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public LoginInterceptor loginInterceptor() {
return new LoginInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/api/admin/common/user/login/**",
"/api/admin/common/user/kaptcha/**"
);
}
}
三、系统任何位置获取当前登录用户方式
CurrentUser currentUser = CurrentUserUtil.currentUser();