场景需求为: gateway给header中存了jwt,jwt存了多个信息,可能有角色,uid,权限等,需要一个注解,在Controller上,使用@JwtClaimParam("userId") Long userId 将jwt中的userId解析出来并注入Controller参数的userId中。
1. 定义注解
import java.lang.annotation.*;
/**
* @author : eben@hi.want.net
* @date : 2023/7/6 17:34
* @description:
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JwtClaimParam {
String value() default "";
}
2. 拦截注解
package net.want.common.annotation.handler;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import net.want.common.annotation.JwtClaimParam;
import org.springframework.core.MethodParameter;
import org.springframework.util.StringUtils;
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;
import java.util.List;
/**
* @author : eben@hi.want.net
* @date : 2023/7/7 15:19
* @description:
*/
public class ProcessedHeaderArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(JwtClaimParam.class) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
JwtClaimParam annotation = parameter.getParameterAnnotation(JwtClaimParam.class);
String claimName = StringUtils.hasText(annotation.value()) ? annotation.value() : parameter.getParameterName();
String token = webRequest.getHeader("jwt");
// 解析JWT并获取声明值
JWT jwt = JWTUtil.parseToken(token);
Class<?> dynamicClass = Class.forName(parameter.getParameter().getParameterizedType().getTypeName());
Object convertedValue = jwt.getPayload(claimName);
if (dynamicClass.equals(List.class)) {
convertedValue = List.of(parameter);
} else {
// 普通类型, INT , LONG, String 之类的
convertedValue = dynamicClass.getDeclaredMethod("valueOf", String.class).invoke(null, convertedValue.toString());
}
return convertedValue;
}
}
其中 convertedValue = dynamicClass.getDeclaredMethod("valueOf", String.class).invoke(null, convertedValue.toString());
意义为: 执行dynamicClass的valueOf方法,对应的入参是convertedValue.toString(),入参类型是 String.class
这里只实现了 对于List和Int,Long,String等基本类型,不知道怎么全自动反射。
3. 将拦截器注入WebConfig
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 注册自定义的参数解析器
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers){
argumentResolvers.add(new RequestStringParamHandlerMethodArgumentResolver());
argumentResolvers.add(new ProcessedHeaderArgumentResolver());
WebMvcConfigurer.super.addArgumentResolvers(argumentResolvers);
}
}
4. 任意Controller上使用
public ResultVO<list> userUploadFile(MultipartFile[] files, @JwtClaimParam("userId") Long userId)</list
ps:Gateway中添加jwt代码如下
webclientBuilder.build()
.get()
.uri("lb://xxxxxxxx/open/auth/api/auth/user/info")
.header("token", token)
.exchange()
.flatMap(resp -> resp.bodyToMono(ResultVO.class)
.doOnSuccess(
body -> {
System.out.println("success");
System.out.println(body);
UserInfoResponse userInfoResponse = new UserInfoResponse();
BeanUtil.copyProperties(body.getData(), userInfoResponse);
if (body.getCode() != null && ResultCode.SUCCESS.getCode().equals(body.getCode()) && body.getData() != null) {
Optional.ofNullable(userInfoResponse.getId()).map(i -> exchange.getRequest().mutate().header("userId", i.toString()));
HashMap<String, Object> tokenMap = new HashMap<>();
tokenMap.put("userId", userInfoResponse.getId());
String jwt = JWT.create()
.setPayload("userId", userInfoResponse.getId())
.setKey("testRes".getBytes())
.sign();
exchange.getRequest().mutate().header("jwt", jwt);
} else {
log.error("获取admin-uid失败-1, 考虑token是否过期/正确");
throw new RuntimeException("获取admin-uid失败");
}
}
))
.doOnError(i -> {
log.error("获取admin-uid失败-2, 考虑token是否过期/正确");
throw new RuntimeException("获取admin-uid失败");
})
.block();
发表回复