- 作者:老汪软件技巧
- 发表时间:2024-10-10 17:03
- 浏览量:
前言:
在现代的Web应用开发中,前后端分离架构逐渐成为主流。而在这样架构下,安全性就显得尤为重要,尤其是用户登录验证的实现。JWT(JSON Web Token)凭借其无状态、跨语言支持等特性,成为了非常流行的登录验证方案。今天,我们将详细介绍如何在Spring Boot和Vue组合的项目中,通过JWT和拦截器来实现登录验证功能,确保只有登录成功的用户才能访问相应的后台资源。
具体操作:一、后端:SpringBoot配置jjwt依赖1.1、添加依赖
首先,需要在pom.xml文件中添加 jjwt 和一些其他的依赖
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwtartifactId>
<version>0.9.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>2.0.49version>
dependency>
1.2、JWT工具类
创建一个JwtUtils工具类,用来生成和解析token
ps:其中这里面保存的密钥和有效时间可以在application.properties中保存,并创建一个类获得这些数据便于调用
public class JwtUtils {
private static String signKey = "xctest";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分负载 payload 中存储的内容
* @return
*/
public static String generateJwt(Map<String, Object> claims){
String jwt = Jwts.builder()
.addClaims(claims)
.signWith(SignatureAlgorithm.HS256, signKey)
.setExpiration(new Date(System.currentTimeMillis() + expire))
.compact();
return jwt;
}
/**
* 解析JWT令牌
* @param jwt JWT令牌
* @return JWT第二部分负载 payload 中存储的内容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
接着可以使用postman进行检验,查看返回的信息是否正确
这里返回了对应的对象信息以及token,测试正确
编辑
1.3、登录接口
在登录接口中实现对应逻辑,当用户成功登录后生成一个token并返回给前端
@PostMapping("/login")
public ResponseEntity> login(@RequestBody LoginRequest loginRequest) {
User user = userService.selectByPhone2(loginRequest.getPhoneNumber());
if (user != null && userService.checkPassword(loginRequest.getPassword(), user.getUserPassword())) {
if (user.getUserRole().equals(loginRequest.getRole())){
//登录成功后生成token
Map<String, Object> claims = new HashMap<>();
claims.put("username",user.getUserName());
claims.put("userphone",user.getUserPhone());
claims.put("userrole",user.getUserRole());
String jwt = JwtUtils.generateJwt(claims);
//向前端返回对象和token信息
return ResponseEntity.ok(ApiResponse.success("登录成功",Map.of("user", user, "token", jwt)));
}else {
return ResponseEntity.status(401).body(ApiResponse.error("角色不匹配"));
}
} else {
return ResponseEntity.status(401).body(ApiResponse.error("登录失败,账号或密码密码错误"));
}
}
1.4、JWT拦截器
创建一个拦截器LoginCheckInterceptor继承HandlerInterceptor并重写其中的三个方法,一般只重写preHandle,其他两个方法默认即可
重写preHandle方法时一般是遵循下面过程:
1.获取请求的url路径
2.判断路径是否为登录或者注册界面(如果是就放行,这两个界面一般不需要登录后获取token;如果不是则继续操作对token进行验证),前面两步操作可省略,因为后面也会对路径进行检查
3.获取前端返回的令牌信息
4.验证当前令牌是否存在,根据令牌的长度来判断,为null则说明令牌不存在并向前端返回错误信息(此操作可省略)
5.验证当前令牌是否有效,判断令牌是否过时等,若令牌无效会抛出异常,此时继续向前端返回错误信息
6.放行
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取请求的url路径
String url = request.getRequestURL().toString();
log.info("获取到的url路径为:{}",url);
//判断url路径中是否存在login,存在则说明是登录操作放行
if(url.contains("login")||url.contains("register")){
log.info("当前是登录操作,放行。。。");
return true;
}
//若是其他操作,则获取令牌并验证
String jwt =request.getHeader("token");
//先验证令牌是否存在(判断长度是否为null)
if (!StringUtils.hasLength(jwt)) {
log.info("当前token为空,返回未登录信息");
response.setContentType("application/json; charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);//设置HTTP响应状态码为401,表示未授权
JSONObject json = new JSONObject();
json.put("success",false);
json.put("message","未登录状态(token不存在)");
response.getWriter().write(json.toString());
return false;
}
//再验证令牌是否正确(看是否抛出异常)
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
response.setContentType("application/json; charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);//设置HTTP响应状态码为401,表示未授权
JSONObject json = new JSONObject();
json.put("success",false);
json.put("message","未登录状态(token无效)");
response.getWriter().write(json.toString());
return false;
}
//放行
log.info("令牌合法,成功登录放行");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle运行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion运行");
}
}
1.5、注册拦截器
在WebConfig中添加拦截器,确定哪些路径需要被拦截
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
}
}
在postman中进行测试,当不携带token时查询信息,会显示为登录,无法获得信息
编辑
接着我们在请求头中添加上token再进行查询,就可以得到数据了
编辑
编辑
二、前端:Vue实现登录与请求验证2.1、main.js中配置拦截器
在main.js中配置axios后添加上拦截器
// 添加请求拦截器
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers['token'] = token; // 在每个请求中添加token
}
return config;
}, error => {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(response => {
return response;
}, error => {
console.log(error.response)
// 检查响应状态
if (error.response.status === 401) {
// 如果未授权,则跳转到登录界面
localStorage.removeItem('token'); // 清除token
this.$router.push({ name: 'Login' }); // 跳转到登录页面
}
return Promise.reject(error);
});
2.2、index.js中添加路由守卫
index.js中指定公开界面和要授权界面
// 添加路由守卫
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token');
const publicPages = ['/login', '/register']; // 公开页面
const authRequired = !publicPages.includes(to.path); // 需要授权的页面
if (authRequired && !token) {
next({ name: 'Login' }); // 如果未登录,重定向到登录页面
} else {
next(); // 放行
}
});
2.3、管理token信息
在登录界面中,成功登录后会保存token信息,退出界面中,退出时会清除token信息,这里不在赘述
知识点:
拦截器:Spring Boot中的拦截器可以用于在请求进入控制器之前进行处理,如验证请求是否携带合法的Token。
Vue中的Axios拦截器:在每次发出HTTP请求时自动携带Token,并在Token失效时跳转到登录页面,提升用户体验。
总结:
通过这篇教程,我们成功实现了一个基于Spring Boot + Vue的登录验证系统,并使用JWT保证了前后端分离项目的安全性。JWT不仅可以简化会话管理,还能提升系统的扩展性。希望大家能根据项目需求灵活应用JWT,打造更加安全的Web应用。
如果你感觉有帮到你的话,就给我一个点赞收藏吧!你的支持是我的最大动力!!!