参考 B 站楠哥教你学 Java的30 分钟学会 Spring Boot + JWT + Vue视频
H1JWT 介绍
H2什么是 JWT?
JSON Web Token,通过数字签名的方式,以 JSON 对象为载体,在不同的服务终端之间安全的传输信息。
H2JWT 有什么用?
JWT 最常见的场景就是授权认证,一旦用户登录,后续每个请求都将包含 JWT,系统在每次处理用户请求的之前,都要先进行 JWT 安全校验,通过之后再进行处理。
H2JWT 的组成
JWT 由 3 部分组成,用**.**拼接
java
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2MjMyMjM2NzUsImp0aSI6ImQ2MTJjZjcxLWI5ZmUtNGMwNy04MzQwLTViOWViZmMyNjExNyJ9.FOS9Y7rYNdc2AOidnSPrgg2XTYePU0yGZ598h2gtabE
这三部分分别是:
Header
java
{
'typ': 'JWT',
'alg': 'HS256'
}
Payload
java
{
"sub": '1234567890',
"name": 'john',
"admin":true
}
Signature
javascript
var encodedString = base64UrlEncode(header) + "." + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, "secret");
所需依赖
pom.xml
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
H1实现登录认证功能(核心代码)
本次代码以用户 User 为例
H2前端(Vue 3.x)
-
在
Login.vue
里添加代码:js
login() { request.post("/user/login", this.form).then((res) => { if (res.code === "0") { localStorage.setItem('access', JSON.stringify(res.data)) let message = '欢迎"' + res.data.username + '"用户登录' ElMessage.success(message); this.$router.replace('/'); //登录成功之后进行页面的跳转,跳转到首页 } else { ElMessage.error(res.msg); } }); },
-
在
src\router\index.js
添加代码:(按需更改)js
// 路由跳转之前要进行的操作 router.beforeEach((to, from, next) => { //如果当前在登录页面,则把本地存储用户信息移除 if (to.path == "/login" || to.path == "/register") { window.localStorage.removeItem("access"); next(); } else { //如果在其它页面,则将用户信息在数据库里验证一下 let access = JSON.parse(window.localStorage.getItem("access")); if (!access) { ElMessage.warning("请先登录!"); next({ path: "/login" }); } else if (access.role == 1) { //普通用户 //是否在后台页面 if (to.path.startsWith("/back")) { next({ path: "/403" }); } else { //校验token合法性 request .get("/user/checkToken", { headers: { token: access.token, }, }) .then((res) => { if (!res) { ElMessage.error("用户登录信息失效"); next({ path: "/login" }); } next(); }); } } else if (access.role == 2) { //管理员 //校验token合法性 request .get("/admin/checkToken", { headers: { token: access.token, }, }) .then((res) => { if (!res) { ElMessage.error("管理员登录信息失效"); next({ path: "/login" }); } next(); }); } } });
-
添加
src\utils\request.js
:(按需添加)js
import axios from "axios"; const request = axios.create({ baseURL: "/api", // 注意!! 这里是全局统一加上了 '/api' 前缀,也就是说所有接口都会加上'/api'前缀在,页面里面写接口的时候就不要加 '/api'了,否则会出现2个'/api',类似 '/api/api/user'这样的报错,切记!!! timeout: 5000, }); // request 拦截器 // 可以自请求发送前对请求做一些处理 // 比如统一加token,对请求参数统一加密 request.interceptors.request.use( (config) => { config.headers["Content-Type"] = "application/json;charset=utf-8"; // config.headers['token'] = user.token; // 设置请求头 return config; }, (error) => { return Promise.reject(error); } ); // response 拦截器 // 可以在接口响应后统一处理结果 request.interceptors.response.use( (response) => { let res = response.data; // 如果是返回的文件 if (response.config.responseType === "blob") { return res; } // 兼容服务端返回的字符串数据 if (typeof res === "string") { res = res ? JSON.parse(res) : res; } return res; }, (error) => { console.log("err" + error); // for debug return Promise.reject(error); } ); export default request;
在前端解决跨域问题:
-
更改
vue.config.js
代码:(按需添加)js
// 跨域配置 module.exports = { devServer: { port: 8060, // 启动端口号 proxy: { //设置代理,必须填 "/api": { //设置拦截器 拦截器格式 斜杠+拦截器名字,名字可以自己定 target: "http://localhost:6666", //代理的目标地址(后端) changeOrigin: true, //是否设置同源,输入是的 pathRewrite: { //路径重写 "/api": "", //选择忽略拦截器里面的单词 }, }, }, }, };
H2后端(Spring Boot)
-
src/main/java/com.hassan/controller/User.java
:java
//与数据库表名一一对应,必须写 @TableName("user") @Data public class User { @TableId(type = IdType.AUTO) private Integer id; private String username; private String pwd; private String nickname; private String phone; private String email; @TableField(exist = false) private String token; //普通用户为1,管理员为2 @TableField(exist = false) private int role = 1; }
-
新建
src/main/java/com.hassan/util/JwtUtil.java
:java
public class JwtUtil { private static long time = 1000*60*60*24; //有效期 private static String signature = "admin"; //签名 public static String createToken() { JwtBuilder jwtBuilder = Jwts.builder(); String jwtToken = jwtBuilder //header .setHeaderParam("typ", "JWT") .setHeaderParam("alg", "HS256") //payload .claim("username", "admin") .claim("role", "admin") .setSubject("admin-test") .setExpiration(new Date(System.currentTimeMillis()+time)) .setId(UUID.randomUUID().toString()) //signature .signWith(SignatureAlgorithm.HS256, signature) .compact(); return jwtToken; } public static boolean checkToken(String token) { if(token == null) { return false; } try { Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token); } catch (Exception e) { return false; } return true; } }
-
src/main/java/com.hassan/controller/UserController.java
:
java
public class UserController {
@Resource
UserMapper userMapper;
//登录
@PostMapping("/login")
public Result<?> login(@RequestBody User user) {
User res = userMapper.selectOne(Wrappers.<User>lambdaQuery()
.eq(User::getUsername, user.getUsername())
.eq(User::getPwd, user.getPwd()));
if (res == null) {
return Result.error("-1", "用户名或密码错误");
} else {
//添加Token
res.setToken(JwtUtil.createToken());
return Result.success(res);
}
}
//Token校验
@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request) {
String token = request.getHeader("token");
return JwtUtil.checkToken(token);
}
}
-
新建
src/main/java/com.hassan/common/Result.java
文件(按需添加)java
//Json数据 public class Result<T> { private String code; private String msg; private T data; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public Result() { } public Result(T data) { this.data = data; } public static Result success() { Result result = new Result<>(); result.setCode("0"); result.setMsg("成功"); return result; } public static <T> Result<T> success(T data) { Result<T> result = new Result<>(data); result.setCode("0"); result.setMsg("成功"); return result; } public static Result error(String code, String msg) { Result result = new Result(); result.setCode(code); result.setMsg(msg); return result; } }
H2补充
如何取出 localStorage 里的值?
比如:this.user = JSON.parse(window.localStorage.getItem('access'))
结束语:
哎,东拼西凑地把毕设上的登录认证功能给完成了,我太拉了