先说下需求:
前后端分离,登录后前端每次请求带有token,请求后端.希望登录过滤器解析后,能把用户的id直接在controller中获取到
实现方式:
注解形式
1.登录拦截器
public class LoginInterctor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory.getLogger(LoginInterctor.class);
@Resource
private JedisSentinelPool jedisSentinelPool;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//如果不是映射到方法直接通过
if (!(handler instanceof HandlerMethod))
return true;
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
//从header中得到token
AuthorizationToken token = getToken(request);
Jedis jedis = jedisSentinelPool.getResource();
String tokenString = jedis.get(token.getUserId().toString());
if (tokenString.equals(token.getToken())) {
request.setAttribute("loginId", token.getUserId());
return true;
}else{
throw new TalentChainException(ResultCodeEnum.NOT_LOGIN.getCode(), ResultCodeEnum.NOT_LOGIN.getMessage());
}
}
public AuthorizationToken getToken(HttpServletRequest request){
String value = request.getHeader(RequestConstant.AUTHORIZATION);
if (StringUtils.isBlank(value))
value = request.getParameter(RequestConstant.AUTHORIZATION);
if (StringUtils.isBlank(value)) {
value = Optional.ofNullable(request.getAttribute(RequestConstant.AUTHORIZATION))
.map(o -> String.valueOf(o))
.orElse("");
}
AuthorizationToken token = new AuthorizationToken(value);
return token;
}
}
AuthorizationToken会将传入的token解析.与redis中对比后获取当前登录用户的id.
登录过滤器配置
在springmvc.xml中加入.mapping代表过滤所有.exclude-mapping代表除此之外.,下面是说带有special的请求之外请求都将被拦截;
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/**/special/**"/>
<bean class="com.chain.talent.util.aop.interceptor.LoginInterctor"/>
</mvc:interceptor>
</mvc:interceptors>
2.自定义参数解析器
a.注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentUserId {
}
b.解析器
public class CurrentUserIdResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
if (methodParameter.getParameterType().isAssignableFrom(Long.class) &&
methodParameter.hasParameterAnnotation(CurrentUserId.class)) {
return true;
}
return false;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
return (Long)nativeWebRequest.getAttribute("loginId", RequestAttributes.SCOPE_REQUEST);
}
}
代码比较简单.只是将request中的loginId去除.放入使用@CurrentUserId中
c.解析器配置
<!-- mvc注解驱动 -->
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="com.chain.talent.util.aop.interceptor.CurrentUserIdResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
3.controller中使用
@RequestMapping(value = "/userCenter" ,method = RequestMethod.GET)
JsonResult MineInfo(@CurrentUserId Long userId){
return JsonResult.SUCCESS().putResult("user",userService.getJobHunterInfoByUserId(userId));
}
代码不多.
但是最初我是想在登录的过滤器中修改request中的请求参数.将userId放入请求参数中.失败后查了一些文章说: 为了安全,不建议修改请求参数.由于水平有限我不会改源码.于是,我想在controller中的方法接受前多放一些参数,发现了一个有趣的注解:
@modelattribute..有兴趣的可以看一下这个注解.我认为它对于我现在的业务并不是很符合.然后在github上发现了一个项目.我认为很不错的解决了我的问题.
如果上述代码比较杂乱.没有看懂.可以直接到github上看别人的源码;
https://github.com/ScienJus/spring-restful-authorization