一般在前后端分离项目中,我们都是通过token去获取用户信息,然后这样我感觉不够骚气,刚好偶然一次机会一个朋友告诉了我他们那如何设计处理的。大致处理如下,使用的时候,直接获取即可。
import org.springframework.stereotype.Component;
import com.spring.framework.entity.SysUserEntity;
import java.util.Optional;
/**
* @author ljw
* 2021年6月19日17:04:083
*/
@Component
public class DataContextSupport {
public static final ThreadLocal<SysUserEntity> dataContext = new ThreadLocal<>();
private static final SysUserEntity DATA_PERMISSIONS = new SysUserEntity();
/**
* 设置当前用户数据权限
*/
public static void setDataPermissions(SysUserEntity dataPermissions) {
dataContext.set(dataPermissions);
}
/**
* 获取当前用数据权限
*/
public static SysUserEntity getDataPermissions() {
return Optional.ofNullable(dataContext.get()).orElse(DATA_PERMISSIONS);
}
/**
* 移除当前用户数据权限
*/
public static void close() {
dataContext.remove();
}
}
定义一个过滤器,每次请求完之后把对应的用户信息存放起来,由于我使用的是shiro,刚好可以直接利用shiro的tokenFilter,于是我就在userRealm认证成功之后放入,效果类似。
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
JwtToken jwtToken = (JwtToken)authenticationToken;
String token = (String) jwtToken.getPrincipal();
//token是否存在
if (StringUtils.isEmpty(token)||!token.startsWith("Bearer")) {
throw new AuthenticationException(" 非法请求,请先登录! ");
}
token = token.replace("Bearer ", "");
//token是否有效
String username = JwtUtil2.getUsername(token);
String random = JwtUtil2.getUuid(token);
if(StringUtils.isEmpty(username)||StringUtils.isEmpty(random)) {
throw new AuthenticationException(" 认证无效,请重新认证! ");
}
//验证token是否合法
if(!JwtUtil2.verify(token, username,random)) {
throw new AuthenticationException(" 认证无效,请重新认证! ");
}
LoginUser loginUser = (LoginUser) redisUtil.get("LOGIN"+username);
if(loginUser==null) {
throw new AuthenticationException(" 登录过期,请重新登录! ");
}
if(!loginUser.getUuid().equals(random)) {
throw new AuthenticationException(" 在别处登录,请重新登录! ");
}
redisUtil.expire("LOGIN" + username, 60 * 30);
DataContextSupport.setDataPermissions(loginUser.getSysUserEntity());//将用户信息存入
return new SimpleAuthenticationInfo(loginUser.getSysUserEntity(),jwtToken.getPrincipal(),getName());
}
为了避免内存泄漏问题,我们可以在每次请求执行完 之后释放掉。
定义拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 释放资源
* @author ljw
*
*/
public class DataContextInterceptor implements HandlerInterceptor {
/**
* 拦截前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 拦截后
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
DataContextSupport.close();
}
}
新增配置类,让拦截器生效
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import com.spring.framework.user.DataContextInterceptor;
@Configuration
public class WebMvcConfigurer implements org.springframework.web.servlet.config.annotation.WebMvcConfigurer {
//添加拦截器
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new DataContextInterceptor()).addPathPatterns("/**") ;
}
}
测试效果