关于token做登陆拦截的思路整理:
使用到的技术:token,redis,jackson
maven加载token
编写token的生成和解析静态工具类
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
@Slf4j
public class TokenUtils {
private static final String secret="miyao";
/**
*依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.15.0</version>
</dependency>
*/
/**
* 生成token
* @param uuid
* @return
*/
public String createToken(String uuid){
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
String token = JWT.create()
.withIssuer("qianfaren")
.withSubject("token")
.withClaim("uuid",uuid)
.sign(algorithm);
return token;
} catch (JWTCreationException exception){
//Invalid Signing configuration / Couldn't convert Claims.
log.error("token生成失败");
}
return "";
}
/**
* 解析token
* @param token
* @return
*/
public DecodedJWT getJwt(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("qianfaren")
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
return jwt;
} catch (JWTVerificationException exception){
//Invalid signature/claims
log.error("token解析错误");
}
return null;
}
/**
* 获取uuid
* @param token
* @return
*/
public String UUidGetByJwt(String token){
DecodedJWT jwt = getJwt(token);
if(jwt!=null){
return jwt.getClaim("uuid").asString();
}
return null;
}
/**
* 从请求中获取uuid
* @param httpServletRequest
* @return
*/
public String getUUidFromToken(HttpServletRequest httpServletRequest){
String authorization = httpServletRequest.getHeader("Authorization");
String s = authorization.split(" ")[1];
DecodedJWT jwt = getJwt(s);
String uuid = jwt.getClaim("uuid").asString();
return uuid;
}
}
登陆步骤:
前端发送登录请求之后
-> 验证登陆成功
-> 把验证查找到的用户信息使用jackson转为字符串
-> 以生成的uuid为key,用户字符串为value储存在redis中
-> 给前端返回生成的token -> 前端储存到本地 :使用cookie存储,有vue-cookie和js-cookie,百度即可
验证步骤: 前端每次发送请求都要携带之前储存 在本地的token(方法见AXIOS统一文档)
存在请求头中发送到后端
/*
* 封装axios
* */
import axios from "axios";
import { Notification } from 'element-ui';
//创建
const instance = axios.create({
baseURL: 'http://localhost:10001/',//统一请求
timeout: 3000,
});
// Add a request interceptor请求之前
instance.interceptors.request.use(function (config) {
// Do something before request is sent
config.headers.Authorization存的值key,后台根据这个拿="Bearer "+从cookie获取token
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
//请求之后
instance.interceptors.response.use(function (response) {
let {status, message, data} = response.data
if(status==20000){
return data
}else {
Notification({
title: '警告',
message: message,
type: 'warning'
});
return Promise.reject(false);
}
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
export default instance;
-> 后端配置拦截器,拦截除登陆,首页,获取验证的其他请求
-> (此时会出现一个问题:我们只能在拦截器中获取请求头中的token,
如果想要在其他方法中获取, 需要每个方法中写入HttpServletRquest,太麻烦,
我们需要一个工具类,可以随时获取全局的HttpServletRquest,
以便于我们解析其中携带的请求头中的token)
package com.sm.qy28.contorller.lanjieqi;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
public class SevletUtils {
/**
* 获取全局的Request
* @return
*/
public static HttpServletRequest getRequest(){
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
return servletRequestAttributes.getRequest();
}
}
编写解析token静态方法,获取Rquest中请求头中携带的token,解析出uuid,
再用UUid为key查询 Redis中储存的用户信息字符串 -> 查询成功就代表为登录状态
如果查询不成功,或解析就不成功,不应该在拦截器中返回false,而是应该抛出异常,并处理
此时,如果抛了异常,前端就会出现跨域问题,因为如果抛异常,那么你在spring里配置的跨域处理cores就没有作用,因为我们自定义的拦截器会在cores过滤器之前执行,如果我们的拦截器直接抛异常,那么就不会进入cores过滤器,自然就不会处理跨域问题,解决方案见跨域处理