说明
客户端的接口一般都是需要用户登录才能访问信息的,验证用户身份是否登录,获取用户信息。一般做法就是客户端把token存进header中,服务器查询token是否失效和正确(服务器存token可以存进redis中,也可以使用JWT),然后通过token获取用户信息并正常访问接口。
自定义拦截器
拦截器和过滤器的区别就不过多描述了,我的理解就是拦截器是在具体的方法层次(springmvc)拦截做逻辑处理,过滤器是针对请求做的逻辑处理,过滤器先于拦截器执行。
先自定义一个注解@ApiAuth,表示接口权限认证
/**
* 自定义注解接口权限认证
*/
@Target(ElementType.METHOD)// 作用于方法上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiAuth {
}
然后再自定义拦截器,需要继承HandlerInterceptorAdapter,里面有三个方法,我们就重写preHandle()方法,该方法会在控制器方法执行前执行。返回值为true走正常逻辑,false不再继续执行。
@Component
public class ApiAuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
ApiAuth annotation = method.getAnnotation(ApiAuth.class);
if (annotation != null) {
String token = request.getHeader(Constants.AUTH_TOKEN);
if (checkAuth(token)) {
return true;
} else {
// 这里就是返回json数据,AjaxResult是我自定义的返回json数据的方法
AjaxResult ajaxResult = AjaxResult.error("没有权限,请登录!");
ServletUtils.renderString(response, JSON.marshal(ajaxResult));
return false;
}
} else {
return true;
}
} else {
return super.preHandle(request, response, handler);
}
}
/**
* 校验用户访问权限
* @param token
* @return
*/
private boolean checkAuth(String token) {
// 可以使用redis存取token,判断token值是否有效
// 也可以用JWT存取token
if (token) {// 判断token是否有效,自己写方法实现
return false;
}
return true;
}
}
自定义参数解析器
先自定义取值标签@UserInfo,用于根据token取值
/**
* 自定义注解获取用户信息
* 作用于方法里的参数上面
* 用于获取的用户的信息,如果是long,则获取userId,如果是User对象,则获取用户对象
*/
@Target(ElementType.PARAMETER)// 作用于方法里的参数上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserInfo {
}
自定义参数解析器,实现HandlerMethodArgumentResolver,url请求进来走完拦截器后会在进入方法前执行supportsParamet()方法。
public class UserInfoHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
/**
* url请求进来后走完其他一些拦截器等之后会在进入方法之前执行supportsParameter依次传入要请求方法的参数
* @param methodParameter
* @return
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
if (methodParameter.hasParameterAnnotation(UserInfo.class)) {
return true;
}
return false;
}
/**
* supportsParameter()返回值为true时,会执行本方法
* @param methodParameter
* @param modelAndViewContainer
* @param nativeWebRequest
* @param webDataBinderFactory
* @return
* @throws Exception
*/
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String token = request.getHeader(Constants.AUTH_TOKEN);
System.out.println("parameter:" + token);
Class<?> parameterType = methodParameter.getParameterType();
if (parameterType.isAssignableFrom(SysUser.class)) {
SysUser user = new SysUser();
user.setUserId(1L);
user.setUserName("昂克");
return user;
} else if (parameterType.isAssignableFrom(Long.class)) {
// getUserId(token)
Long userId = 1L;
return userId;
}
return null;
}
}
springboot配置自定义拦截器和参数解析器
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
@Autowired
private ApiAuthInterceptor apiAuthInterceptor;
/**
* 自定义拦截规则
*/
@Override
public void addInterceptors(InterceptorRegistry registry)
{
registry.addInterceptor(apiAuthInterceptor).addPathPatterns("/**");
}
/**
* 自定义参数解析器
* @param resolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new UserInfoHandlerMethodArgumentResolver());
}
}
测试
@RestController()
@RequestMapping("api")
public class ApiTestController extends BaseController {
@ApiAuth
@GetMapping("test")
public AjaxResult test(@UserInfo Long id, @UserInfo SysUser user) {
Map map = new HashMap();
map.put("id", id);
map.put("user", user);
return success(map);
}
}