springboot-vue-JWT使用
后端引入依赖:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency>
JWT工具类:
package com.tangzhe.util; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.Date; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureException; /** * API调用认证工具类,采用RSA加密 */ public class JWTUtils { private static RSAPrivateKey priKey; private static RSAPublicKey pubKey; private static class SingletonHolder { private static final JWTUtils INSTANCE = new JWTUtils(); } public synchronized static JWTUtils getInstance(String modulus, String privateExponent, String publicExponent) { if (priKey == null && pubKey == null) { priKey = RSAUtils.getPrivateKey(modulus, privateExponent); pubKey = RSAUtils.getPublicKey(modulus, publicExponent); } return SingletonHolder.INSTANCE; } public synchronized static void reload(String modulus, String privateExponent, String publicExponent) { priKey = RSAUtils.getPrivateKey(modulus, privateExponent); pubKey = RSAUtils.getPublicKey(modulus, publicExponent); } public synchronized static JWTUtils getInstance() { if (priKey == null && pubKey == null) { priKey = RSAUtils.getPrivateKey(RSAUtils.modulus, RSAUtils.private_exponent); pubKey = RSAUtils.getPublicKey(RSAUtils.modulus, RSAUtils.public_exponent); } return SingletonHolder.INSTANCE; } /** * 获取Token * @param uid 用户ID * @param exp 失效时间,单位分钟 * @return */ public static String getToken(String uid, int exp) { long endTime = System.currentTimeMillis() + 1000 * exp; return Jwts.builder().setSubject(uid).setExpiration(new Date(endTime)) .signWith(SignatureAlgorithm.RS512, priKey).compact(); } /** * 获取Token * @param uid 用户ID * @return */ public String getToken(String uid) { long endTime = System.currentTimeMillis() + 1000 * 60 * 1440; return Jwts.builder().setSubject(uid).setExpiration(new Date(endTime)) .signWith(SignatureAlgorithm.RS512, priKey).compact(); } /** * 检查Token是否合法 * @param token * @return JWTResult */ public JWTResult checkToken(String token) { try { Claims claims = Jwts.parser().setSigningKey(pubKey).parseClaimsJws(token).getBody(); String sub = claims.get("sub", String.class); return new JWTResult(true, sub, "合法请求", ResponseCode.SUCCESS_CODE.getCode()); } catch (ExpiredJwtException e) { // 在解析JWT字符串时,如果‘过期时间字段’已经早于当前时间,将会抛出ExpiredJwtException异常,说明本次请求已经失效 return new JWTResult(false, null, "token已过期", ResponseCode.TOKEN_TIMEOUT_CODE.getCode()); } catch (SignatureException e) { // 在解析JWT字符串时,如果密钥不正确,将会解析失败,抛出SignatureException异常,说明该JWT字符串是伪造的 return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode()); } catch (Exception e) { return new JWTResult(false, null, "非法请求", ResponseCode.NO_AUTH_CODE.getCode()); } } public static class JWTResult { private boolean status; private String uid; private String msg; private int code; public JWTResult() { super(); } public JWTResult(boolean status, String uid, String msg, int code) { super(); this.status = status; this.uid = uid; this.msg = msg; this.code = code; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public boolean isStatus() { return status; } public void setStatus(boolean status) { this.status = status; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } } }
前端页面文件:
<!-- 登录 --> <div> <p>用户名:<input v-model="username" /></p> <p>密码:<input v-model="password" /></p> <button @click="login">登录</button> </div>
...
login: function() {
axios.post('http://localhost:8889/user/login', {
username: this.username,
password: this.password,
})
.then(function (response) {
if (response.data.status) {
alert(response.data.token);
} else {
alert("登录失败");
}
})
.catch(function (error) {
console.log(error);
});
}
后端controller:
@PostMapping("/login") public Object login(@RequestBody LoginInfo loginInfo) { Map<String, Object> result = new HashMap<>(); String token = userService.login(loginInfo); if (token == null) { result.put("status", false); } else { result.put("status", true); result.put("token", token); } return result; }
后端service:
public String login(LoginInfo loginInfo) { User user = userRepository.findByUsernameAndPassword(loginInfo.getUsername(), loginInfo.getPassword()); if (user == null) { return null; } String token = JWTUtils.getInstance().getToken(user.getId() + ""); return token; }
测试登录:
登录成功返回token
token本地存储:
存储在前端
login: function() { axios.post('http://localhost:8889/user/login', { username: this.username, password: this.password, }) .then(function (response) { if (response.data.status) { alert(response.data.token); // token本地存储 localStorage.setItem("token", response.data.token); } else { alert("登录失败"); } }) .catch(function (error) { console.log(error); }); }
// 从html本地存储中拿出token,设置到全局请求头中
axios.defaults.headers.common['Authorization'] = localStorage.getItem("token");
这样每次发送请求就能带上token的请求头了
后端解析请求头获取token,并借助jwt工具类解密出当前登录用户id:
public class LoginInfoUtils { /** * 获取当前登录用户id */ public static String getLoginUserId(HttpServletRequest request) { String authorization = request.getHeader("Authorization"); if (StringUtils.isNotBlank(authorization)) { JWTUtils.JWTResult result = JWTUtils.getInstance().checkToken(authorization); if (result.isStatus()) { return result.getUid(); } } return null; } }
后端控制台输出当前登录用户ID:
@GetMapping("/list") public List<User> list(HttpServletRequest request) { // 获取当前登录用户id System.out.println("当前用户ID: " + LoginInfoUtils.getLoginUserId(request)); return userService.findAll(); }
若还没登录则输出:当前用户ID: null
用户登录则输出:当前用户ID: 6
这样,前端发送请求时,请求头中带有后端登录接口返回的token值,
后端可以从请求头中获取token并通过JWT解密获得当前登录用户id,就可以在后端获取当前登录用户了。