发布于 

SpringBoot拦截器中获取token中的用户信息并通过注解可以在任何一个Controller上获取到用户基本信息

前端调用后端Controller方法时,进入Controller方法后,经常需要获取当前登录用户的信息,便于一些后续的用户操作(比如保存时需要自动填入当前登录用户的用户名)。

通常的做法是,前端将token信息放入请求头中,后端拿到请求头中的token后,再将token解析成用户信息。

解决方案

token解析工具类方法

校验token有效性:boolean isValid = tokenUtils.isValid(token);

解析token为User:User user = tokenUtils.getUserInfoByToken(token);

直接在需要使用用户信息的地方调用token解析方法获取User对象。

WebMvcConfigurer + HandlerInterceptor + HandlerMethodArgumentResolver

Spring内部的一种配置方法,通过用java代码代替xml配置Bean,可以通过实现WebMvcConfigurer接口自定义一些MVC相关的Handler,Interceptor等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Configuration
public class SecurityAutoConfiguration implements WebMvcConfigurer{

@Override
public void addInterceptors(InterceptorRegistry registry) {
// addInterceptor:添加一个实现HandlerInterceptor了接口的拦截器实例
// addPathPatterns:用于设置拦截器的过滤路径规则
registry.addInterceptor(getAuthInterceptor()).addPathPatterns("/**");
}

@Bean
public AuthInterceptor getAuthInterceptor() {
// 声明AuthInterceptor拦截器Bean,需实现HandlerInterceptor接口
return new AuthInterceptor();
}

@Bean
public CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver() {
// 声明自定义方法参数解析器
return new CurrentUserMethodArgumentResolver();
}

@Override
public void addArgumentResolvers(List argumentResolvers) {
// 添加CurrentUserMethodArgumentResolver参数解析器
argumentResolvers.add(currentUserMethodArgumentResolver());
}

}

自定义HandlerInterceptor进行权限校验,token解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AuthInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tokenId = request.getHeader(CommonDefs.AUTHORIZATION);
if (!StringUtils.hasLength(tokenId)) {
return false;
}

// 校验token是否有效
boolean isValid = tokenUtils.isValid(token);
if (!isValid) {
return false;
}
// 转换token为User实例
User user = tokenUtils.getUserInfoByToken(token);
if (user == null) {
return false;
}
// 将用户信息user保存到request属性中
request.setAttribute("current_user", user);
return true;
}
}

自定义@CurrentUser注解,并加入到controller接口中

1
2
3
4
5
6
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CurrentUser {
String value() default "current_user";
}
1
2
3
4
5
6
@GetMapping("/getUserInfo")
@ApiOperation(value = "查询用户信息")
public Result getUserInfo(@ApiIgnore @CurrentUser User user) {
// 通过@CurrentUser修饰,user即为当前登录用户信息
return Result.ok(user);
}

自定义HandlerMethodArgumentResolver,将request中的User传给@CurrentUser

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Controller参数解析器
public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver {
public CurrentUserMethodArgumentResolver() {
}

@Override
// 判断Controller层中的参数,是否满足条件,满足条件则执行resolveArgument方法,不满足则跳过
public boolean supportsParameter(MethodParameter parameter) {
// 如果controller中的参数有CurrentUser注解修饰,则执行resolveArgument方法
return parameter.hasParameterAnnotation(CurrentUser.class);
}

@Override
// Controller中的参数满足supportsParameter()条件时执行
// 将返回值赋值给Controller层中的这个参数
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 获取CurrentUser注解
CurrentUser currentUserAnnotation = (CurrentUser)parameter.getParameterAnnotation(CurrentUser.class);
// 将request请求中的"current_user"属性赋值给当前参数
// "current_user"保存的是当前登录用户的信息
return webRequest.getAttribute(currentUserAnnotation.value(), 0);
}
}

如果没生效,排查一下 implements WebMvcConfigurer 的配置类 是否将解析器注入到了SpirngMVC

如果没有 可参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.chentawen.springbootall.config.annotation.UserIdResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
* @author admin
*/
@Configuration
public class IntercaptorConfig implements WebMvcConfigurer {

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserIdResolver());
}

}