获取当前用户信息的几种方式

获取当前用户信息的几种方式

说明:在开发中,我们经常需要获取当前操作的用户信息,如创建用户、创建订单时,我们需要记录下创建人,本文介绍获取当前用户信息的三种方式。

方式一:使用ThreadLocal

ThreadLocal本质上是一个Map,键是当前线程,值是存入的信息。我们可以在用户登录,校验用户信息后,将所需要的用户信息存入到ThreadLocal中,如用户ID、用户Token等,然后在需要的时候直接使用即可。

如下,在preHandle()方法中,将当前用户的ID存入到TokenThreadLocal对象中,

@Component

public class TokenInterceptor implements HandlerInterceptor {

@Value("${token.key}")

private String tokenKey;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

// 获取请求头 拿到Token

String token = request.getHeader("Token");

String authToken = request.getHeader("authentication");

if (StrUtil.isAllEmpty(token,authToken)){

return responseHandler(response);

}

// 校验Token的合法性和有效性

JWT jwt = JWTUtil.parseToken(StrUtil.isBlank(token) ? authToken : token);

try {

// 校验Token是否合法 校验Token是否过期

if (!(jwt.setKey(tokenKey.getBytes()).verify() && jwt.validate(0))){

return responseHandler(response);

}

} catch (Exception e) {

// 抛出自定义异常 Token是非法的

// throw new RuntimeException(e);

return responseHandler(response);

}

// 把Token的信息解析出来放到ThreadLocal

Long id = Convert.toLong(jwt.getPayload("id"));

// 设置本地线程池中的用户ID

TokenThreadLocal.set(id);

// 放行

return true;

}

本地线程对象,TokenThreadLocal

/**

* 本地线程对象

*

* 存放用户ID

*/

public class TokenThreadLocal {

/**

* 创建一个ThreadLocal对象

*/

private static final ThreadLocal THREAD_LOCAL= new ThreadLocal<>();

/**

* 添加一个数据

* @param key

*/

public static void set(Long key){

THREAD_LOCAL.set(key);

}

/**

* 获取一个数据

* @return

*/

public static Long get(){

return THREAD_LOCAL.get();

}

/**

* 删除一个数据

*/

public static void remove(){

THREAD_LOCAL.remove();

}

}

需要的时候,直接调用其get()方法,下面是使用AOP+自定义注解实现对创建、更新操作字段的填充;

注意,需要在afterCompletion()方法中调用ThreadLocal的remove()方法,避免内存泄漏;

方式二:通过拦截器和相应注解实现

如果项目中,登录校验框架使用的是Shiro,有一种更方便的方式,如下:

第一步:创建一个自定义注解,如LoginInfo,表示登录用户的信息,注意元注解的属性;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 登录用户

* @author

*/

@Target(value = ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

public @interface LoginInfo {

}

第二步:创建MVC的配置类,注入一个在线用户解析对象,后面实现;

import org.decent.modules.integral.resolver.LoginUserArgumentResolver;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;

import java.util.List;

/**

* web设置

* @author

*/

@Configuration

public class WebConfig implements WebMvcConfigurer {

@Resource

private LoginUserArgumentResolver loginUserArgumentResolver;

@Override

public void addArgumentResolvers(List resolvers) {

resolvers.add(loginUserArgumentResolver);

}

}

第三步:创建在线用户解析类,其中获取当前用户的信息使用的是Shiro框架的方法,SecurityUtils.getSubject().getPrincipal(),该方法返回的是一个Object类型的对象;

import org.apache.shiro.SecurityUtils;

import org.decent.modules.integral.annotation.LoginInfo;

import org.springframework.core.MethodParameter;

import org.springframework.stereotype.Component;

import org.springframework.web.bind.support.WebDataBinderFactory;

import org.springframework.web.context.request.NativeWebRequest;

import org.springframework.web.method.support.HandlerMethodArgumentResolver;

import org.springframework.web.method.support.ModelAndViewContainer;

/**

* 登录解析实现

*

* @author

*/

@Component

public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {

@Override

public boolean supportsParameter(MethodParameter methodParameter) {

return methodParameter.hasParameterAnnotation(LoginInfo.class);

}

@Override

public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {

return SecurityUtils.getSubject().getPrincipal();

}

}

第四步:创建一个在线用户的JavaBean,存放一些可能会用得上的属性;

import lombok.Data;

/**

* 在线用户信息

*/

@Data

public class LoginUser {

/**

* 登录人id

*/

private String id;

/**

* 登录人账号

*/

private String username;

/**

* 登录人名字

*/

private String realname;

}

第五步:在需要使用的接口上,直接使用注解即可。当请求访问该接口时,会被前面的拦截器拦截住,然后把当前用户的信息取出来并封装到JavaBean对象中,非常方便;

@PostMapping(value = "/add")

public Result add(@LoginInfo LoginUser loginUser) {

......

}

方式三:使用Redis存储用户信息

这种方式思路和第一种相同,当用户通过校验时,将用户信息查询出来并存起来,需要的时候再取出来用。当然,使用Redis存储比ThreadLocal更灵活一点,可以设置有效时间。实现如下:

第一步:登录验证通过,将用户信息存入Redis;

@PostMapping("/login")

public Result counterLogin(@RequestBody LoginBody LoginUser){

// 登录

LoginUser userInfo = sysLoginService.login(LoginUser.getUsername(), LoginUser.getPassword(),LoginUser.getCounterType());

// 创建Token并返回

return Result.success(tokenService.createToken(userInfo));

}

@Autowired

private RedisService redisService;

// 定义有效时间,为720 * 60 秒,即12小时

private final static long EXPIRE_TIME = 720 * 60;

/**

* 创建令牌

*/

public Map createToken(LoginUser loginUser){

// 生成token

String token = IdUtils.fastUUID();

loginUser.setToken(token);

loginUser.setUserid(loginUser.getSysUser().getUserId());

loginUser.setUsername(loginUser.getSysUser().getUserName());

// 保存用户token

Map map = new HashMap();

map.put("token", token);

map.put("loginUser",loginUser);

// 将该用户的信息存入到Redis中

redisService.setCacheObject(token, loginUser, EXPIRE_TIME, TimeUnit.SECONDS);

return map;

}

RedisService类相关方法

/**

* spring redis 工具类

**/

@Component

public class RedisService{

@Autowired

public RedisTemplate redisTemplate;

/**

* 缓存基本的对象

*/

public void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit){

redisTemplate.opsForValue().set(key, value, timeout, timeUnit);

}

/**

* 获得缓存的基本对象

*/

public T getCacheObject(final String key){

ValueOperations operation = redisTemplate.opsForValue();

return operation.get(key);

}

}

第三步:需要时,根据当前用户的Token,去Redis中取出该用户的信息;

/**

* 根据用户Token获取用户身份信息

*

* @return 用户信息

*/

public LoginUser getLoginUser(String token){

if (StringUtils.isNotEmpty(token)){

String userKey = getTokenKey(token);

LoginUser user = redisService.getCacheObject(userKey);

return user;

}

return null;

}

用户的Token是需要放在Request对象里面的,所以可以再写一个TokenService对象,用来获取当前用户的Token,并调用RedisService获取当前用户信息,进行进一步的封装。

总结

以上是三种获取当前用户信息的方式,可以根据实际情况选择;

🌸 相关推荐

世界杯史上最严监管下 竞彩为何仍创新高?
365彩票最新版app下载

世界杯史上最严监管下 竞彩为何仍创新高?

📅 06-28 👀 3448
十二星座中哪些星座最泼辣
家庭版microsoft365

十二星座中哪些星座最泼辣

📅 06-27 👀 3389
在线对数计算器
365提前结束投注

在线对数计算器

📅 06-30 👀 8212