JWT身份验证的流程
-
用户登录: 用户向服务器提供他们的用户名和密码。
-
服务器验证:服务器接收到请求,验证用户名和密码。
-
生成JWT:如果用户名和密码验证通过,服务器将创建一个 JWT。 JWT 包含了一些数据(称为声明),例如用户 ID、用户名、令牌过期时间等。然后,服务器将对 JWT 进行签名,并将其发送回用户。
-
用户存储JWT:用户接收到 JWT,并将其存储在某个位置,例如Web浏览器的localStorage中。
-
发送带有JWT的请求:之后,每当用户向服务器发送请求(例如获取数据)时,他们都将在请求头的 Authorization 字段中包含 JWT。
-
服务器验证JWT:服务器接收到用户的请求,并从 Authorization 头中提取 JWT。然后,服务器验证该 JWT:它会检查 JWT 是否已经过期,验证签名是否有效,还可能验证一些其他的声明。如果 JWT 有效,服务器就知道这个请求是合法的,并继续处理请求。
-
返回响应:一旦服务器处理完用户的请求,它就会将响应发送回用户。
-
刷新JWT:如果 JWT 过期了,服务器可能会返回一个新的 JWT 给用户,或者让用户重新登陆,以便他们可以继续发送合法的请求。
JWT的安全性
如果你改变了 JWT 中的任何部分(包括头部、负载或签名),然后尝试验证它,你可能会遇到几个问题:
-
签名错误:JWT 的签名是根据头部和负载计算得出的。如果你修改了头部或负载的任何部分,那么签名就不再有效,JWT 的验证将会失败。这是因为签名是为了确保 JWT 的头部和负载没有被篡改。
-
格式错误:如果你修改了 JWT 的格式(例如,删除了某个部分,或者改变了部分之间的点号分隔符),那么 JWT 可能无法被正确解析,这将导致错误。
-
负载数据错误:如果你修改了负载中的数据(这是 JWT 中包含的实际信息,如用户 ID、过期时间等),那么这些数据可能无法被正确解析,或者可能导致验证错误(例如,如果你把过期时间改为了过去的时间,那么 JWT 将被视为已经过期)。
SpringBoot中使用JWT
添加maven依赖文章来源:https://www.toymoban.com/news/detail-569276.html
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
package xin.students.springbootpro;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.UUID;
@SpringBootTest
class SpringBootProApplicationTests {
// 设置 token 过期时间为24小时
private long time = 1000 * 60 * 60 * 24;
// 使用 HS256 算法生成一个安全的密钥
private SecretKey signature = Keys.secretKeyFor(SignatureAlgorithm.HS256);
@Test
public void createToken() {
// 构建一个 JWT Builder
JwtBuilder jwtBuilder = Jwts.builder();
// 生成 JWT Token
String jwtToken = jwtBuilder
.setHeaderParam("typ", "JWT") // 设置 JWT 类型
.setHeaderParam("alg", "HS256") // 设置签名算法
.claim("username", "tom") // 添加 username 到载荷中(自定义的key:value)
.claim("role", "admin") // 添加 role 到载荷中(自定义的key:value)
.setSubject("admin-test") // 设置主题
.setExpiration(new Date(System.currentTimeMillis() + time)) // 设置过期时间
.setId(UUID.randomUUID().toString()) // 设置 JWT ID,通常是随机生成的
.signWith(signature) // 签名 JWT,用以验证其完整性
.compact(); // 压缩 JWT 到一个 compact, URL-safe string
System.out.println(jwtToken);
System.out.println("下面是解密后的原文------------------------------------");
// 解析生成的 token
parseToken(jwtToken);
}
public void parseToken(String token) {
// 创建一个 JWT 解析器
JwtParser jwtParser = Jwts.parserBuilder()
.setSigningKey(signature)
.build();
// 解析 token
Jws<Claims> claimsJws = jwtParser.parseClaimsJws(token);
// 获取载荷
Claims claims = claimsJws.getBody();
// 打印载荷中的各种信息
System.out.println(claims.get("username")); // 打印 username对应的值
System.out.println(claims.get("role")); // 打印 role对应的值
System.out.println(claims.getId()); // 打印 JWT ID
System.out.println(claims.getSubject()); // 打印主题
System.out.println(claims.getExpiration()); // 打印过期时间
}
}
文章来源地址https://www.toymoban.com/news/detail-569276.html
Controller示例
package xin.students.springbootpro.util;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.UUID;
public class JwtUtil {
// 有效时间为5秒
private static long time = 1000 * 5;
private static SecretKey signature = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static String createToken() {
JwtBuilder jwtBuilder = Jwts.builder();
// 生成 JWT Token
String jwtToken = jwtBuilder
.setHeaderParam("typ", "JWT") // 设置 JWT 类型
.setHeaderParam("alg", "HS256") // 设置签名算法
.claim("username", "admin") // 添加 username 到载荷中(自定义的key:value)
.claim("password", "123") // 添加 username 到载荷中(自定义的key:value)
.claim("role", "admin") // 添加 role 到载荷中(自定义的key:value)
.setSubject("admin-test") // 设置主题
.setExpiration(new Date(System.currentTimeMillis() + time)) // 设置过期时间
.setId(UUID.randomUUID().toString()) // 设置 JWT ID,通常是随机生成的
.signWith(signature) // 签名 JWT,用以验证其完整性
.compact(); // 压缩 JWT 到一个 compact, URL-safe string
System.out.println(signature);
return jwtToken;
}
public static Boolean checkToken(String token) {
// 判断 token 是否为空
if (token == null) {
return false;
}
try {
// 解析并验证 token
Jws<Claims> jws = Jwts.parserBuilder()
.setSigningKey(signature) // 使用之前的签名秘钥验证 token
.build()
.parseClaimsJws(token);
// 从 jws 中获取到 token 的载荷
Claims claims = jws.getBody();
String username = claims.get("username", String.class);
String password = claims.get("password", String.class);
String role = claims.get("role", String.class);
System.out.println("username " + username);
System.out.println("password " + password);
return username.equals("admin") && password.equals("123");
} catch (Exception e) {
return false;
}
}
}
Vue登录示例
const fun = () => {
axios.get("http://localhost:81/login", {params: ruleForm}).then(res => {
if (res.data === null || res.data === '')
console.log("密码不匹配")
else {
console.log(res.data)
localStorage.setItem("access-admin", JSON.stringify(res.data));
router.push("/");
}
}).catch(error => {
console.log(error);
})
}
Vue路由守卫校验是否登录示例
import {createRouter, createWebHistory, createWebHashHistory} from 'vue-router'
import axios from "axios";
const routes = [
{
path: '/',
name: 'home',
component: () => import('@/components/Home.vue')
},
{
path: '/about',
name: 'about',
component: () => import(/* webpackChunkName: "about" */ '@/components/About.vue')
},
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "about" */ '@/components/Login.vue')
},
{
path: '/error',
name: 'error',
component: () => import(/* webpackChunkName: "about" */ '@/components/Error.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
router.beforeEach((to, from, next) => {
if (to.path.startsWith("/login")|| to.path.startsWith("/error")) {
window.localStorage.removeItem("access-admin");
next();
} else {
let admin = JSON.parse(window.localStorage.getItem("access-admin"));
if (!admin) {
next({path: "/login"})
} else {
axios({
url: "http://localhost:81/checkToken",
method: "get",
headers: {
token: admin.token
}
}).then((res) => {
console.log(res.data);
console.log(typeof res.data);
if (res.data === false) {
console.log("校验失败!");
next({path: "/error"});
}else{
next();
}
}).catch((err) => {
console.error(err);
next({path: "/error"});
})
}
}
})
export default router
到了这里,关于SpringBoot使用JWT进行身份验证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!