本文说明SpringBoot + Vue集成JWT实现登录认证
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.10.3version>
dependency>
<dependency>
<groupId>net.sf.json-libgroupId>
<artifactId>json-libartifactId>
<version>2.4version>
<classifier>jdk15classifier>
dependency>
/**
* @author hanmingzhi
* @date 2022/8/14 18:47
**/
public class TokenUtil {
//token到期时间30分钟(根据需求改)
private static final long EXPIRE_TIME= 30*60*1000;
//密钥 (随机生成,可以从网上找到随机密钥生成器)
private static final String TOKEN_SECRET="MD9**+4MG^EG79RV+T?J87AI4NWQVT^&";
/** 生成token */
public static String createToken(User user){
String token=null;
try {
Date expireAt=new Date(System.currentTimeMillis()+EXPIRE_TIME);
token = JWT.create()
//发行人
.withIssuer("auth0")
//存放数据
.withClaim("email",user.getEmail())
.withClaim("id",user.getId())
//过期时间
.withExpiresAt(expireAt)
.sign(Algorithm.HMAC256(TOKEN_SECRET));
} catch (IllegalArgumentException| JWTCreationException je) {}
return token;
}
/** token验证 */
public static Boolean checkToken(String token){
try {
//创建token验证器
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT decodedJWT=jwtVerifier.verify(token);
System.out.println("认证通过:");
System.out.println("id: " + decodedJWT.getClaim("id").asInt());
System.out.println("email: " + decodedJWT.getClaim("email").asString());
System.out.println("过期时间:" + decodedJWT.getExpiresAt());
} catch (IllegalArgumentException | JWTVerificationException e) {
//抛出错误即为验证不通过
return false;
}
return true;
}
}
/**
* @author hanmingzhi
* @date 2022/8/14 18:46
**/
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//跨域请求会首先发一个option请求,直接返回正常状态并通过拦截器
if(request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
String token = request.getHeader("token");
String requestUrl = request.getServletPath();
if (token!=null){
boolean result= TokenUtil.checkToken(token); // 验证token
if (result){
System.out.println("通过拦截器:"+requestUrl); // 可以输出接口是否通过拦截器
return true;
}
}
response.setCharacterEncoding("utf-8");
response.setContentType("application/json; charset=utf-8");
try {
JSONObject json=new JSONObject();
json.put("msg","token认证失败");
json.put("code","500");
response.getWriter().append(json.toString());
System.out.println("认证失败,未通过拦截器:"+requestUrl);
} catch (Exception e) {
return false;
}
/**
* 还可以在此处检验其他操作
*/
return false;
}
}
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Autowired
private TokenInterceptor tokenInterceptor;
// 解决跨域问题
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.maxAge(1800)
.allowedOrigins("*");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePath = new ArrayList<>();
//这里用来排除拦截的接口,例如登录前调用的接口
excludePath.add("/userLogin"); //登录
excludePath.add("/userRegister"); //注册
excludePath.add("/static/**"); //静态资源
excludePath.add("/checkToken"); // 检测token是否正确
excludePath.add("/findEmail"); // 查询邮箱是否注册
excludePath.add("/getEmailCode"); //获取邮箱验证码
registry.addInterceptor(tokenInterceptor) // 注册拦截器
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
}
/**
* @author hanmingzhi
* @date 2022/8/13 19:29
**/
@RestController
public class UserController {
@Autowired
UserMapper userMapper ;
// 用户登录
@PostMapping("userLogin")
public JSONObject userLogin(String email, String password){
User user = userMapper.getUserByEmail(email);
String token = "" ;
String msg="";
JSONObject res = new JSONObject();
if(user != null){
if(user.getPassword().equals(password)){
msg="登录成功,正在进入首页。。。";
token= TokenUtil.createToken(user); // 登录成功后,创建一个token
res.put("user",user);
}else{
msg="登录失败,请检查密码";
}
}
res.put("token",token);
res.put("msg",msg);
return res;
}
// 检验token
@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request){
System.out.println("前端访问页面验证token");
String token = request.getHeader("token");
return TokenUtil.checkToken(token);
}
}
// 登录
onLogin() {
console.log("进入登录")
let _this = this
axios({
method: 'post',
url: 'http://localhost:8210/userLogin',
params: {
email: this.formObj.email,
password: this.formObj.password
},
header: {
'content-type': 'application/x-www-form-urlencoded',
},
}).then(function (response) {
// 登录成功,保存token 和用户信息
if (response.data.token != '') {
ElMessage({ message: response.data.msg,type: 'success',})
localStorage.setItem("token", response.data.token)
localStorage.setItem("user", JSON.stringify(response.data.user))
_this.$store.commit('saveUser', response.data.user)
_this.$store.commit('saveToken', response.data.token)
setTimeout(() => {
_this.$router.replace({ path: '/index' })
}, 2000);
}else{
ElMessage({ message: response.data.msg,type: 'error',})
return
}
});
},
//路由设置
router.beforeEach((to, from, next) => {
if (to.path === '/') { // 如果跳转登录页面,则移除token
localStorage.removeItem('token')
localStorage.removeItem('user')
next()
} else {
let token = localStorage.getItem('token');
if (token === null || token === '') { //token不存在页跳转到登录页面
router.replace({path:'/'})
} else {
// 检验token是否正确
axios({
url: 'http://localhost:8210/checkToken', //在controller中写一个接口用来token校验
method: 'get',
//将token信息保存在header里
headers: {
token: token
}
}).then((response) => {
if (!response.data) {
console.log('检验失败')
router.replace({path:'/'}) // 如果token失效,返回到登录页面
}
})
next();
}
}
})
本文是根据其他博主的文章进行总结,有错误的地方希望指出!
结束!