Post's cover

参考 B 站楠哥教你学 Java30 分钟学会 Spring Boot + JWT + Vue视频

H1JWT 介绍

H2什么是 JWT?

JSON Web Token,通过数字签名的方式,以 JSON 对象为载体,在不同的服务终端之间安全的传输信息。

H2JWT 有什么用?

JWT 最常见的场景就是授权认证,一旦用户登录,后续每个请求都将包含 JWT,系统在每次处理用户请求的之前,都要先进行 JWT 安全校验,通过之后再进行处理。

H2JWT 的组成

JWT 由 3 部分组成,用**.**拼接

javaeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2MjMyMjM2NzUsImp0aSI6ImQ2MTJjZjcxLWI5ZmUtNGMwNy04MzQwLTViOWViZmMyNjExNyJ9.FOS9Y7rYNdc2AOidnSPrgg2XTYePU0yGZ598h2gtabE

这三部分分别是:

Header

java{ 'typ': 'JWT', 'alg': 'HS256' }

Payload

java{ "sub": '1234567890', "name": 'john', "admin":true }

Signature

javascriptvar 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)

  1. Login.vue里添加代码:

    jslogin() { 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); } }); },
  2. 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(); }); } } });
  3. 添加src\utils\request.js:(按需添加)

    jsimport 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;

在前端解决跨域问题:

  1. 更改vue.config.js代码:(按需添加)

    js// 跨域配置 module.exports = { devServer: { port: 8060, // 启动端口号 proxy: { //设置代理,必须填 "/api": { //设置拦截器 拦截器格式 斜杠+拦截器名字,名字可以自己定 target: "http://localhost:6666", //代理的目标地址(后端) changeOrigin: true, //是否设置同源,输入是的 pathRewrite: { //路径重写 "/api": "", //选择忽略拦截器里面的单词 }, }, }, }, };

H2后端(Spring Boot)

  1. 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; }
  2. 新建src/main/java/com.hassan/util/JwtUtil.java

    javapublic 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; } }
  3. src/main/java/com.hassan/controller/UserController.java

javapublic 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); } }
  1. 新建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'))

结束语

哎,东拼西凑地把毕设上的登录认证功能给完成了,我太拉了

Prev

Next

Related Posts