1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
7、如果前端拿到状态码为-10000,就清除token信息并跳转到登录页面鉴权登陆
package com.example.api_project.JWT;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import java.util.Map;
public class JWT {
private static final String SECRET = "XX#$%()(#*!()!KL<>?N<:{LWPW";
private static final String EXP = "exp";
private static final String PAYLOAD = "payload";
//加密,传入一个对象和有效期
public static String sign(T object, long maxAge) {
try {
final JWTSigner signer = new JWTSigner(SECRET);
final Map claims = new HashMap();
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(object);
claims.put(PAYLOAD, jsonString);
claims.put(EXP, System.currentTimeMillis() + maxAge);
return signer.sign(claims);
} catch(Exception e) {
return null;
}
}
//解密,传入一个加密后的token字符串和解密后的类型
public static T unsign(String jwt, Class classT) {
final JWTVerifier verifier = new JWTVerifier(SECRET);
try {
final Map claims= verifier.verify(jwt);
if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {
long exp = (Long)claims.get(EXP);
long currentTimeMillis = System.currentTimeMillis();
if (exp > currentTimeMillis) {
String json = (String)claims.get(PAYLOAD);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(json, classT);
}
}
return null;
} catch (Exception e) {
return null;
}
}
}
2.编写拦截器
package com.example.api_project.JWT;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSON;
import com.example.api_project.model.ResponseData;
import com.example.api_project.model.Result;
import com.example.api_project.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSONObject;
//自定义拦截器
public class TokenInterceptor implements HandlerInterceptor{
/**
* preHandle()返回true后,afterCompletion()才会执行
*/
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,
Object handler, Exception arg3) throws Exception {
}
/**
* 该方法在调用controller方法后,DispatcherServlet渲染视图之前被执行
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView model) throws Exception {
}
/**
* 发起请求前调用
* 该方法返回false的话,将不会往下执行
*/
//拦截每个请求
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
response.setCharacterEncoding("utf-8");
String token = request.getHeader("token");
System.out.println("preHandle....." + token);
Result responseData;
//token存在
if(null != token) {
User login = JWT.unsign(token, User.class);//解码
String userId = request.getHeader("userId");//获取userId
if(null != userId && null != login) {
//一致,返回true 正常执行
if(userId.equals(login.getUserId())) {
return true;
}
//解密token后的userId与用户传来的userId不一致,一般都是token过期
else{
responseData = ResponseData.authError();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
//有一个或者多个为空
else
{
responseData = ResponseData.authError();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
//token不存在
else
{
responseData = ResponseData.authError();
responseMessage(response, response.getWriter(), responseData);
return false;
}
}
//请求不通过,返回错误信息给客户端
private void responseMessage(HttpServletResponse response, PrintWriter out, Result responseData) {
response.setContentType("application/json; charset=utf-8");
String json = JSONObject.toJSONString(responseData);
out.print(json);
out.flush();
out.close();
}
}
3.配置拦截器
package com.example.api_project.JWT;
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 WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//设置拦截路径,排除路径,优先级等
registry.addInterceptor(new TokenInterceptor())
.excludePathPatterns("/api/login/**").order(11)
.addPathPatterns("/api/user/**");
}
}
4.在loginController中的使用
//登录
@RequestMapping("/login")
@ResponseBody
public Result login(User user) {
User temp= userService.selectForLogin(user);
if(temp!=null){
User u = userService.findOneUser(user);
//给用户jwt加密生成token【//创建JWT令牌】
String token = JWT.sign(u, 60L* 1000L* 30L);
//封装成对象返回给客户端
Result responseData = new Result<>();
responseData.putDataValue("userId", user.getUserId());
responseData.putDataValue("token", token);
responseData.putDataValue("user", u);
responseData.Result();
return responseData;
}else{
return ResponseData.error("账号或密码错误!");
}
}
1.配置request
// 2.请求拦截器
service.interceptors.request.use(config => {
config.data = JSON.stringify(config.data);
config.headers = {
'Content-Type':'application/json' //配置请求头
}
const token = localStorage.getItem('token');
const userId = localStorage.getItem('userId');
if(token){
// config.params = {'userId':userId}
config.headers.userId = userId
config.headers.token= token
}
return config
}, error => {
Promise.reject(error)
})
2.配置response
// 3.响应拦截器
service.interceptors.response.use(response => {
var token = response.headers['token'];
//有token
if(token){
window.vm.$store.commit('token',{token:token});
}
if (response.data.code == -10000) {
localStorage.clear()
router.push({ name: 'login' })
Message({
message: "鉴权登陆失败",
type: "error",
});
}
return response
}, error => {})
这样就可以了啦!~好像也不难呢!~springboot项目不需要再写那么多乱七八糟的配置文件 ~~~
关于返回类型的统一封装,可以参考这篇笔记
Java后端返回结果统一封装http://t.csdn.cn/6Ba23