我们通过实现WebMvcConfigurer的addInterceptors方法来增加自定义拦截器
InterceptorConfig.java
import com.wwk.xinyao.common.intecepter.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* Description: 配置所有拦截器类
* Author wwk
* Date 2023/7/11 15:36
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor).addPathPatterns("/chatApi/test");
}
}
首先我们需要考虑哪些Api需要认证登录态才可以访问,比如获取用户的个人信息,假设我们没有做拦截器,来来接这一类的Api那么所有人都可通过它来取到任何一个用户的用户信息,这个就完全没有了安全性.
所以我们需要增加这样的拦截器来控制我们到底需要对外暴露哪些Api提供给用户使用,哪些Api是需要认证之后才能提供给用户的
有了上面的拦截器的配置其实,其实实现起来不困难了,我们首先要知道拦截器就是,当我请求一个Api的地址之后,拦截器就会根据地址来判断是否需要拦截,假设地址是需要拦截的,就会进入拦截器先进行判断能都通过,通过了在放开,如果没有通过,用户就得不到想要的数据
InterceptorConfig.java
// 注册loginInterceptor拦截器,拦截'/chatApi/test'URI的请求
registry.addInterceptor(loginInterceptor).addPathPatterns("/chatApi/test");
LoginInterceptor
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.wwk.xinyao.chat.annotation.PrivateApi;
import com.wwk.xinyao.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
/**
* 登录验证拦截器
* Author wwk
* Date 2023/7/11 15:38
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
private static final String AUTH_TOKEN_HEADER = "X-Auth-Token";
@Resource
private UserService userService;
@Value("${xy.http.header-token-prefix}")
private String tokenPrefix; ;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取用户传来的token信息,通过请求头
if(isPrivateApi(handler)){ //是私有的需要验证登录态
String token = getToken(request);
Long uid = userService.checkLogin(token);
return !Objects.isNull(uid);
}
return true;
}
/**
* 根据注解来判api是不是私有的,如果是就需要认证登录态
* @return 是否不是私有的
*/
private boolean isPrivateApi(Object handler){
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod= (HandlerMethod) handler;
PrivateApi methodAnnotation = handlerMethod.getMethodAnnotation(PrivateApi.class);
return methodAnnotation != null;
}
throw new IllegalStateException("Not supported for handler "+handler);
}
/**
* 获取前段传来的封装好的token
* @param request Http请求
* @return 真正的token token?token:null
*/
private String getToken(HttpServletRequest request){
String safeToken = request.getHeader(AUTH_TOKEN_HEADER);
if(StringUtils.isNotBlank(safeToken)){
return safeToken.split(" ")[1];
}
return null;
}
}
注意:这里我们可以看出,前端会通过请求头携带token的方式把封装好的token发送给后端进行校验,当后端进入到拦截器之后,首先我们会去判断这个Api是否是私有的,也就是不允许被访问的,如果它是私有的我们就需要通过一些手段来验证用户是否可以访问这个Api,当然这个拦截器里我们验证的是用户的登录态,如果是私有的,我们就需要先去验证登录态,通过了在执行api的方法,不通过就直接拦截,如果不是私有的就直接放行
这里我的做法是自定义个注解,可以通过给Api加上指定的注解来判断,Api的私有性
com/wwk/xinyao/chat/annotation/PrivateApi.java
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 是否是私有的Api(如果是就要验证登录态)
* Author wwk
* Date 2023/7/11 16:13
*/
@Target({METHOD})
@Retention(RUNTIME)
public @interface PrivateApi {
boolean value() default true;
}
@GetMapping("/test")
@PrivateApi // 代表api是私有的,不写注解就是公共的
public String test(){
System.out.println("123");
return "ok";
}