前端部分:封装了axios进行请求拦截
class Http {
service: any;
constructor(config: TOption) {
//实例化请求配置
this.service = axios.create(config);
//请求拦截 Authorization自定义名字
this.service.interceptors.request.use(
(config: AxiosRequestConfig) => {
loading = ElLoading.service({ fullscreen: true,text:'加载中...' });
console.log(token.value);
if (token.value) {
(config.headers as AxiosRequestHeaders).Authorization = token.value;
}
return config;
},
(error: any) => {
loading.close();
return Promise.reject(error);
}
);
完整代码:
import axios, {
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
} from "axios";
import { ElMessage, ElLoading } from "element-plus";
import { storeToRefs } from "pinia";
import appStore from "@/store/appStore";
let { token } = storeToRefs(appStore());
const state = {
ok: 0,//请求成功状态码
401:"ERR_BAD_REQUEST"
};
//返回数据规则
interface IResponseData<T> {
status: number;
message?: string;
data: T;
code: string;
}
//请求默认配置规则
type TOption = {
baseURL: string;
timeout: number;
};
//默认配置
const config = {
baseURL: "",
timeout: 30 * 1000,
withCredentials: true,
};
let loading:any = null;
class Http {
service: any;
constructor(config: TOption) {
//实例化请求配置
this.service = axios.create(config);
//请求拦截 Authorization自定义名字
this.service.interceptors.request.use(
(config: AxiosRequestConfig) => {
loading = ElLoading.service({ fullscreen: true,text:'加载中...' });
console.log(token.value);
if (token.value) {
(config.headers as AxiosRequestHeaders).Authorization = token.value;
}
return config;
},
(error: any) => {
loading.close();
return Promise.reject(error);
}
);
//响应拦截
this.service.interceptors.response.use(
(response: AxiosResponse) => {
loading.close();
const data = response.data;
const { code } = data;
if (code == undefined) {
//如果没有返回状态码,直接返回数据,针对于返回数据为blob类型
return response;
} else if (code !== 0) {
ElMessage.error(data.message);
return Promise.reject(data);
}
// code == 0 的时候,提取我们只关注的Api数据data
return response.data.data;
},
(error: any) => {
loading.close();
if(error.code==state[401]){
ElMessage.error("请求失败:"+error.message);
setTimeout(() => {
localStorage.removeItem('com.beiyou')
window.location.href = '/#/login'
},1000);
}
return Promise.reject(error);
}
);
}
get<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.get(url, { params, ...data });
}
post<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.post(url, params, data);
}
put<T>(url: string, params?: object, data = {}): Promise<IResponseData<T>> {
return this.service.put(url, params, data);
}
delete<T>(
url: string,
params?: object,
data = {}
): Promise<IResponseData<T>> {
return this.service.delete(url, { params, ...data });
}
}
export default new Http(config);
后端进行验证
首先自定义注解排除token校验注解类
为不需要校验 token 的方法定义注解
@Documented //标记注解
@Target() //指定作用在方法上 对方法拦截
@Retention() //作用域 在运行时有效
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoAuthorization {
String value() default "";
}
自定义的token秘钥
= great123
编写拦截器token验证的拦截器
1.实现HandlerInterceptor接口重写preHandle方法
2.获取正在运行的方法上面,是否有@NoAuthorization注解,如果有就结束执行,不拦截,不校验token
3.获取前端传来的token,如果有就进行验证,没有就直接抛出401交给前端处理
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTUtil;
import com.beimao.annotation.NoAuthorization;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {
//由于注册器那边是new的新对象,所以拦截器这边不能注册到IOC容器里面
//这边采用构造方法的形式传参给注册器,由注册器注入到IOC容器里面
private String tokenKey;
public TokenInterceptor(String tokenKey) {
this.tokenKey = tokenKey;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
//handler是object类型不能直接调用,如果不强转可以用反射().getMethod()
HandlerMethod handlerMethod = (HandlerMethod) handler;
//判断有没有注解
NoAuthorization noAuthorization = handlerMethod.getMethod().getAnnotation(NoAuthorization.class);
if (noAuthorization != null) {
//如果有该注解,证明该方法不需要token验证;
return true;
}
}
//获取token 前端起的名字Authorization
String token = request.getHeader("Authorization");
//如果token不为空,进行token验证
if (StrUtil.isNotEmpty(token)) {
// 证token verify(toen,秘钥.getBytes) hu-tool工具类 返回布尔类型 验证内容是否相当和是否过期
boolean pass = JWTUtil.verify(token, tokenKey.getBytes());
if (pass == false) {
//验证失败,返回401
response.setStatus(401);
return false;
} else {
//解析token
JWT jwt = JWTUtil.parseToken(token);
return true;
}
}
//没有token,直接返回401
response.setStatus(401);
return false;
}
}
最后进行token拦截器注册
import com.beimao.interceptor.TokenInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Value("${}")
private String tokenKey;
@Override
public void addInterceptors(InterceptorRegistry registry) {
TokenInterceptor loginInterceptor = new TokenInterceptor(tokenKey);
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/api/**"); //拦截请求的url前缀
//.excludePathPatterns("/css/**","/images/**","/js/**");// 放行
}
}