一、自定义拦截器
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();