功能简介
拦截所有添加了我们自定义的注解的方法,并将userId和userMobile放入HttpServletRequest,之后通过对应的注解取值。
包格式
首先我们来先定义三个注解
根据需求其实UserId和UserMobile可以不要,不影响拦截器的使用
package com.xxx.core.annotation;
import javax.ws.rs.NameBinding;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@NameBinding
public @interface UserAuthenticate
{
/**
* 是否需要校验访问权限 默认不校验
*
* @return
*/
boolean permission() default false;
}
package com.xxx.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserId {
}
package com.xxx.core.annotation;
import java.lang.annotation.*;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserMobile {
}
常量类
package com.xxx.core.handler;
public class HeaderCons {
/**
* 用户ID
*/
public static final String USER_ID = "H-User-Id";
/**
* 用户手机号
*/
public static final String USER_MOBILE = "H-User-Mobile";
}
拦截器
package com.xxx.core.filter;
import com.xxx.exception.FastRuntimeException;
import com.xxx.core.annotation.UserAuthenticate;
import com.xxx.core.handler.HeaderCons;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Objects;
public class TestFilter extends HandlerInterceptorAdapter {
private final Logger logger = LoggerFactory.getLogger(TestFilter.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
logger.info("request请求地址path[{}] uri[{}]", request.getServletPath(),request.getRequestURI());
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
UserAuthenticate userAuthenticate = method.getAnnotation(UserAuthenticate.class);
//如果没有加注解则userAuthenticate为null
if (Objects.nonNull(userAuthenticate)) {
Long userId= getUserId(request);
//userAuthenticate.permission()取出permission判断是否需要校验权限
if (userId == null || (userAuthenticate.permission() && !checkAuth(userId,request.getRequestURI()))){
throw new FastRuntimeException(20001,"No access");
}
}
return true;
}
/**
* 根据token获取用户ID
* @param request
* @return
*/
private Long getUserId(HttpServletRequest request){
//添加业务逻辑根据token获取用户UserId
request.getHeader("H-User-Token");
Long userId = 1L;
String userMobile = "18888888888";
request.setAttribute(HeaderCons.USER_ID,userId);
request.setAttribute(HeaderCons.USER_MOBILE,userMobile);
return userId;
}
/**
* 校验用户访问权限
* @param userId
* @param requestURI
* @return
*/
private boolean checkAuth(Long userId,String requestURI){
//添加业务逻辑根据UserId获取用户的权限组然后校验访问权限
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 {}
}
package com.xxx.core;
import com.xxx.core.filter.TestFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class WebAppConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 可添加多个,这里选择拦截所有请求地址,进入后判断是否有加注解即可
registry.addInterceptor(new TestFilter()).addPathPatterns("/**");
}
}
如果不需要使用UserId和UserMobile这两个注解到这里已经结束了。不过为了方便业务层的使用直接获取用户的id、mobile等信息我这里就加上了
添加如下类即可取出我们在拦截器中set进去的值
package com.xxx.core.handler;
import com.xxx.core.annotation.UserId;
import org.springframework.core.MethodParameter;
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 javax.servlet.http.HttpServletRequest;
public class UserIdMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UserId.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return servletRequest.getAttribute(HeaderCons.USER_ID);
}
}
package com.xxx.core.handler;
import com.xxx.core.annotation.UserMobile;
import org.springframework.core.MethodParameter;
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 javax.servlet.http.HttpServletRequest;
public class UserMobileMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(UserMobile.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return servletRequest.getAttribute(HeaderCons.USER_MOBILE);
}
}
以上类是根据你定义的注解来建设的取出放在request里面的值,如果有多个就再加就行了
package com.xxx.core.filter;
import com.xxx.core.annotation.UserId;
import com.xxx.core.annotation.UserMobile;
import com.xxx.core.handler.UserIdMethodArgumentResolver;
import com.xxx.core.handler.UserMobileMethodArgumentResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
public class FilterAutoConfiguration {
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({UserId.class, UserMobile.class})//多个用逗号隔开
protected static class ArgumentResolverAutoConfiguration extends WebMvcConfigurerAdapter {
protected ArgumentResolverAutoConfiguration() {
}
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
//可添加多个
argumentResolvers.add(new UserIdMethodArgumentResolver());
argumentResolvers.add(new UserMobileMethodArgumentResolver());
}
}
}
大功告成 接下来我们看看如何使用
package com.xxx.controller;
import com.xxx.common.response.Response;
import com.xxx.common.Urls;
import com.xxx.core.annotation.UserAuthenticate;
import com.xxx.core.annotation.UserId;
import com.xxx.core.annotation.UserMobile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Validated
@RestController
public class TestAuthController {
@UserAuthenticate
@GetMapping(value = Urls.Test.TEST)
public Response testAuth(@UserId Long userId,@UserMobile String userMobile) {
System.out.println("userId : "+ userId + " userMobile :" + userMobile);
return new Response();
}
}
浏览器输入地址 后台打印
userId : 1 userMobile :18888888888
下一篇带来如何解决获取request中body内容后,导致字符流关闭,后续controller无法获取的问题