先上代码 再看解释😊
后端:
第一步:
引入pom依赖(我这里是jdk1.8引入的jjwt)
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
第二步
这是全部的创建token和解析token
package com.example.hyzn.demos.utils;
import cn.hutool.core.lang.UUID;
import io.jsonwebtoken.*;
import java.util.Date;
public class JwtUtil {
private static long time= 1000*60*60*24;//设置的过期时间是一天
private static String signature="admin";
//创建token的代码
public static String createToken(){
JwtBuilder jwtBuilder = Jwts.builder();
String stringJwtBuilder = jwtBuilder
//header
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//patload
.claim("userName", "Shen")
.claim("role", "admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis() + time))
.setId(UUID.randomUUID().toString())
//signature
.signWith(SignatureAlgorithm.HS256, signature)
.compact();
return stringJwtBuilder;
}
//解析token的代码
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;
}
}
第三步
测试entity(必须要有这个Serializable序列化)
package com.example.hyzn.demos.domain.Request;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* 学生表
* @TableName user
*/
@TableName(value ="user")
@Data
public class UserQuest implements Serializable {
/**
* 账号
*/
@TableId
private String userName;
/**
* 密码
*/
private String password;
/**
* token
*/
private String token;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
第四步
后端的controller层这里面设置的是死的账号密码
/**
* @author 32551
*/
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
private final String USERNAME="admin";
private final String PASSWORD="123456";
@PostMapping("/register")
public BaseResponse<Long> userRegister(@RequestBody UserVo userVo) {
if (userVo == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
return ResultUtils.success(userService.userRegister(userVo), "成功");
}
@PostMapping("/login")
public BaseResponse<UserQuest> userLogin(@RequestBody UserQuest userQuest) {
if(USERNAME.equals(userQuest.getSno())&&PASSWORD.equals(userQuest.getPassword())){
userQuest.setToken(JwtUtil.createToken());
return ResultUtils.success(userQuest,"成功");
}
return null;
}
@GetMapping("/checkToken")
public Boolean checkToken(HttpServletRequest request){
String token = request.getHeader("token");
return JwtUtil.checkToken(token);
}
}
第五步
解决跨域问题 (这里面的 .allowedOrigins("http://localhost:9898/#/userLogin","http://localhost:9898/#/chat"是用来拦截前端页面的按自己的需要来)
/**
* 全局跨域处理
*/
@Configuration
public class CoresConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(@NotNull CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedOrigins("http://localhost:9898/#/userLogin", "http://localhost:9898/#/chat")
.allowCredentials(true)
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
};
}
}
这里的后端就大功告成了
前端:
在router配置文件中设置文件跳转问题
这里面配置跳转页面拦截
router.beforeEach((to, from, next) => {
// 允许未登录访问的路径
const openPaths = ['/userLogin', '/chat'];
if (openPaths.includes(to.path)) {
// 如果目标路径是开放路径,直接放行
next();
} else {
// 获取存储在本地的admin对象
let admin = JSON.parse(window.localStorage.getItem('access-admin'));
if (!admin) {
// 如果没有admin对象,跳转到登录页面
next({ path: '/userLogin' });
} else {
// 验证token的合法性
axios({
url: 'http://localhost:7877/user/checkToken',
method: 'get',
headers: {
token: admin.token
}
}).then((response) => {
if (!response.data) {
// 如果token验证失败,跳转到登录页面
console.log('校验失败');
next({ path: '/userLogin' });
} else {
// 如果token验证成功,继续导航
next();
}
}).catch(() => {
// 处理验证请求失败的情况
next({ path: '/userLogin' });
});
}
}
});
再设置login页面
主要看js代码就好了
前端你们得自己配置跳转路由 我这里安装了router
<template>
<div class="login-page">
<van-nav-bar title="登录" left-arrow />
<div class="login-container">
<h2 class="login-title">欢迎登录移动服务平台</h2>
<van-field class="van-border" v-model="sno" label="" placeholder="请输入身份证号" />
<van-field class="van-border" v-model="password" label="" type="password" placeholder="请输入密码" />
<van-button type="danger" class="login-button" @click="onLogin">登录</van-button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import {showFailToast, showSuccessToast, Toast} from 'vant';
import myaxios from "../Axios/myaxios";
const router=useRouter();
const sno = ref('');
const password = ref('');
const onLogin = () => {
myaxios.post('/user/login', {
sno: sno.value,
password: password.value
}).then(response=>{
console.log(response.data)
if(response.data!=null){
localStorage.setItem('access-admin',JSON.stringify(response.data))//把信息存储到本地
router.push('/')
}
})
};
</script>
<style scoped>
.login-page {
display: flex;
flex-direction: column;
}
.login-container {
flex: 1;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
}
.login-title {
text-align: center;
margin-bottom: 30px;
}
.login-button {
margin-top: 20px;
border-radius: 10px;
}
.van-border {
border: 1px solid #969896;
margin-top: 10px;
border-radius: 10px;
}
</style>
这时候就都完事了
看运行代码结果
那就再来解释解释什么是JWT
jwt的全名称
JSON Web Token(JSON Web令牌)
JWT作用:
-
身份验证:
JWT常用于身份验证。在用户登录时,服务器生成一个JWT并返回给客户端。客户端每次请求时都带上这个JWT,服务器通过验证JWT来确认用户的身份。 -
信息交换:
由于JWT可以携带声明(claims),它们可以用来在不同的服务之间传递信息。这些声明可以包含用户的权限、角色等信息。 -
安全性:
JWT使用签名来确保内容的完整性和真实性。常见的签名算法有HMAC和RSA。通过签名,接收方可以验证消息是否被篡改过。 -
无状态性:
JWT是无状态的,所有的信息都包含在token本身中,不需要在服务器上存储会话信息。这使得JWT在分布式系统中尤其有用。
JWT的结构
JWT由三个部分组成,每一部分使用.
分隔:
-
Header(头部):
- 通常包含两部分:令牌类型(JWT)和使用的签名算法(如HMAC SHA256或RSA)。
{
"alg": "HS256",
"typ": "JWT"
}
-
Payload(负载):
- 包含声明(claims)。声明是关于实体(通常是用户)和其他数据的声明。声明有三种类型:注册声明(如iss, exp, sub, aud)、公开声明和私有声明。
-
{ "sub": "1234567890", "name": "John Doe", "admin": true }
-
Signature(签名):
- 用于验证消息在传输过程中是否被篡改。签名部分是使用header中指定的算法对header和payload进行签名得到的。HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
工作流程
- 用户通过认证(如登录)后,服务器生成JWT并返回给客户端。
- 客户端将JWT存储在本地(如localStorage或cookie)。
- 客户端每次请求时都将JWT包含在HTTP头部中(如Authorization: Bearer <token>)。
- 服务器接收到请求后,验证JWT的有效性和真实性。
- 服务器处理请求并返回响应。