基于springboot完成拦截器,自定义登入检验注解
前文
拦截器类似与面向切面编程(aop)思想,拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例。在请求前通过拦截器验证
集成拦截器
配置拦截器
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.df.samplesub.annotation.PassToken;
import com.df.samplesub.annotation.UserLoginToken;
import com.df.samplesub.entity.User;
import com.df.samplesub.exception.TokenException;
import com.df.samplesub.service.UserService;
import com.df.samplesub.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* @Description:
* @Param:
* @return:
* @Author:
* @Date: 2021/5/31
*/
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
//请求执行前
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
if (userLoginToken.required()) {
// 执行认证
if (token == null) {
throw new TokenException("无token,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
//userId = JWT.decode(token).getAudience().get(0);
userId = JwtUtil.getUserId(token);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
User user = userService.findUserById(userId);
if (user == null) {
throw new TokenException("用户不存在,请重新登录");
}
// 验证 token
//JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC512("www").build();
JwtUtil.checkSign(token);
return true;
}
}
return true;
}
//请求结束执行的
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
//视图渲染完成后执行
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
自定义注解
1.免登入注解
2.登入注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Description: 需要登录才能进行操作的注解UserLoginToken
* @Param:
* @return:
* @Author:
* @Date: 2021/5/31
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Description: 过验证的PassToken
* @Param:
* @return:
* @Author:
* @Date: 2021/5/31
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
注册拦截器
两种方式:
package com.df.samplesub.config;
import com.df.samplesub.fiilter.AuthenticationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Description: 注册拦截器
* @Param:
* @return:
* @Author:
* @Date: 2021/6/9
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
2.启动类配置
//创建登录拦截器
@Bean
public CheckLoginInterceptor checkLoginInterceptor(){
return new CheckLoginInterceptor();
}
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkLoginInterceptor())
.addPathPatterns("/**") //拦截所有请求
.excludePathPatterns("/users/regist")
.excludePathPatterns("/users/login")
.excludePathPatterns("/users/checkPhone")
.excludePathPatterns("/users/sendVerifyCode")
;
}
测试
登入:创建token(此处使用的是jwt)
免登入,不需要携带toktn
@PassToken
@GetMapping("/locationNames")
public ResultBean locationNames() {
List<Arce> locationNames = arceService.getLocationNames();
return ResultBean.success("查询成功",locationNames);
}
需要登入,必须携带有效token
@UserLoginToken
@GetMapping("/locationNames")
public ResultBean locationNames() {
List<Arce> locationNames = arceService.getLocationNames();
return ResultBean.success("查询成功",locationNames);
}
无token
正确的token
token错误或者过期
模拟token过期
效果
此处注销登入,删除缓存中token,将jwt中置为过期