前后端分离jwt登录验证
前后端分离jwt登录验证 (vue + springboot)
方案
- 第一次登录后,前端j将后端返回的token保存在localStorage中
- 以后每次前端访问后端接口时,都从localStorage中取出token加入请求header的Authorization字段
- 后端建立拦截器,拦截每个请求的header中的Authorization字段值,即token,校验token是否过期,如果过期返回响应码401,否则放行
- 前端建立全局响应拦截器,如果拦截到接口请求响应码是401,就跳转到登录页面
login页面
登录成功保存token到localStorage
methods: {
login() {
this.axios.post("/user/login", { username: this.username, password: this.password}).then((response) => {
if (response.data.success) {
localStorage.setItem("token", response.data.msg)
this.$router.push("/xxx")
} else {
this.$message.error(response.data.msg)
}
}).catch((error) => {
this.$message.error(error)
})
}
},
后端接口拦截器
package com.gitee.freakchicken.dbapi.conf;
import com.gitee.freakchicken.dbapi.service.UserService;
import com.gitee.freakchicken.dbapi.domain.User;
import com.gitee.freakchicken.dbapi.util.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
@Component
@Slf4j
public class JwtAuthenticationInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
log.debug(request.getServletPath());
// 跨域的预检请求直接放行
if (request.getMethod().equals(HttpMethod.OPTIONS)) {
return true;
}
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
PrintWriter writer = null;
try {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
String token = request.getHeader("Authorization");
// 执行认证
if (token == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
writer = response.getWriter();
writer.append("\"无token,请重新登录\"");
return false;
}
// 获取 token 中的 userId
String userId = JwtUtils.getAudience(token);
User user = userService.getUserById(Integer.valueOf(userId));
if (user == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
writer = response.getWriter();
writer.append("用户不存在,请重新登录");
return false;
}
// 验证 token
boolean b = JwtUtils.verifyToken(token, user.getPassword());
if (b) {
return true;
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
writer = response.getWriter();
writer.append("token无效,请重新登录");
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (writer != null) {
writer.close();
}
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
}
}
前端main.js
axios.interceptors.request.use(config => {
//拦截所有请求,添加登陆用户的token
if (localStorage.getItem('token')) {
config.headers.Authorization = localStorage.getItem('token');
}
return config
})
//后台用户登陆信息校验不成功就跳转到登录页面
axios.interceptors.response.use(response => {
return response
}, error => {
debugger
if (error.response.status == '401') {
router.push("/login");
} else {
return Promise.reject(error)
}
})
后端登录方法
@RequestMapping("/login")
public ResponseDto login(String username, String password) {
User user = userService.getUser(username, password);
if (user == null) {
return ResponseDto.fail("用户名或者密码错误");
} else {
String token = JwtUtils.createToken(user.getId().toString(), user.getPassword());
return ResponseDto.successWithMsg(token);
}
}
附:jwt工具
package com.gitee.freakchicken.dbapi.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import lombok.extern.slf4j.Slf4j;
import java.util.Calendar;
import java.util.Date;
@Slf4j
public class JwtUtils {
public static String createToken(String userId, String secret) {
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.SECOND, 10);
Date expiresDate = nowTime.getTime();
return JWT.create().withAudience(userId) //签发对象
.withIssuedAt(new Date()) //发行时间
.withExpiresAt(expiresDate) //有效时间
.sign(Algorithm.HMAC256(secret)); //加密
}
/** * 检验合法性,其中secret参数就应该传入的是用户的id * * @param token */
public static boolean verifyToken(String token, String secret) {
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(secret)).build();
try {
jwtVerifier.verify(token);
return true;
} catch (JWTVerificationException e) {
log.error(e.getMessage());
return false;
}
}
/** * 获取签发对象 */
public static String getAudience(String token) {
String audience = null;
try {
audience = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
}
return audience;
}
/** * 通过载荷名字获取载荷的值 */
public static Claim getClaimByName(String token, String name) {
return JWT.decode(token).getClaim(name);
}
}
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
还没有评论,来说两句吧...