JWT实现单点登录(SpringBoot + Vue +axious)
准备阶段:
**登录所需对象** admin{ "username":"", //作为Token "password":"", //作为签名 "nicakname":"", "avatar":"", }
开始阶段
1.导包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
2.创建一个TokenUtils(放在util包下)
public class TokenUtils {
public static String getToken(admin admin){
String token="";
token= JWT.create().withAudience(admin.getUsername()) // 将 username 保存到 token 里面
.withExpiresAt(DateUtil.offsetHour(new Date(),1)) //1小时后token过期(DateUtil是hutool包下的)
.sign(Algorithm.HMAC256(admin.getPassword())); // 以 password 作为 oken的密钥,默认用HMAC256加密
return token;
}
}
3.在admin的相应controller下创建login方法
@PostMapping("/login")
// 1.接收前端传来的登录前Json对象
public Result login(@RequestBody admin admin){
String username = admin.getUsername();
String password = admin.getPassword();
if (username == "" || password == "") {
throw new ServiceException(Constants.CODE_401,"没有输入");
}
// 2.进行登录操作,验证数据库是否有该对象,并得到登录后对象
com.pinkman.management.entity.admin loginAdmin = adminService.login(admin);
// 3.将Token设置进登录后对象
String token = TokenUtils.getToken(loginAdmin);
loginAdmin.setToken(token);
// 4.返回给前端
return new Result(adminService.login(admin) == null?Constants.CODE_200:Constants.CODE_401,"成功",loginAdmin);
}
前端阶段
1.前端登录方法
login() {
var user = {
username: this.username,
password: this.password,
};
this.request
.post("http://localhost:8888/admin/login", user)
.then((res) => {
console.log(res);
if (res.code == "401") {
localStorage.setItem("user", JSON.stringify(res.data));
//储存Token信息
localStorage.setItem("token", res.data.token);
this.$router.push("/");
} else {
this.$message.error("用户名或密码错误");
}
});
tips:前端传给后端时候,正确token:xxx.yyy.zzz,不正确token:"xxx.yyy.zzz"
成功写入本地存储:
2.在前端Vue集成的项目中对axious进行配置
import axios from 'axios'
// request 拦截器
// 可以自请求发送前对请求做一些处理
// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
// 在这里拿到Token信息并且写入到请求的头中去
config.headers['token'] = localStorage.getItem("token");
return config
}, error => {
return Promise.reject(error)
});
Token成功写入请求头
验证阶段
1.前端发送任意带token的请求给后端
2.在后端的config包下的interceptor包下配置相应拦截器(配置校验规则)
@Component
public class JwtHandlerInterceptor implements org.springframework.web.servlet.HandlerInterceptor {
@Autowired
private adminService adminService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
// 0.如果不是映射方法,则直接通过
if (!(handler instanceof HandlerMethod)) {
return true;
}
// 1.先通过token获取相应的用户名
if (StringUtils.isBlank(token)) {
throw new ServiceException(Constants.CODE_401,"无Token,请先登录");
}
String username;
try{
username = JWT.decode(token).getAudience().get(0);
}catch (JWTDecodeException j){
throw new ServiceException(Constants.CODE_401,"Token验证失败");
}
// 2.根据获取到的用户名查询数据库是否存在该用户
admin admin = adminService.getAdminByName(username);
if (admin == null) {
throw new ServiceException(Constants.CODE_401,"用户不存在");
}
// 用户密码加签 验证Token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(admin.getPassword())).build();
// 3.若存在,则对签名进行核验
try {
jwtVerifier.verify(token); // 验证token
} catch (JWTVerificationException e) {
e.printStackTrace();
}
System.out.println("成功验证");
// 4.核验完成则返回true
return true;
}
}
3.在后端的config包下创建拦截器JwtInterceptorConfig配置(让服务器知道拦截器的存在)
// 1.配置注解
@Configuration
// 2.实现WebMvcConfigurer接口
public class InterceptorConfig implements WebMvcConfigurer {
@Bean
public JwtHandlerInterceptor getJwtHandlerInterceptor(){
return new JwtHandlerInterceptor();
}
// 3.重写方法,将jwt拦截器注册进拦截器注册中心(让web应用上下文知道拦截器的存在)
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getJwtHandlerInterceptor())
.addPathPatterns("/**") // 拦截所有请求,通过判断token是否合法来决定是否登录
.excludePathPatterns("/admin/login"); // 排除部分,如,登录请求(必须排除),导入请求,导出请求
}
}
tips:拦截器在初始化时候记得放进spring容器中