JWT教程【JWT】
- 前言
- 版权
- 推荐
- JWT教程
- 1 JWT概述
- 1.1什么是JWT
- 1.2JWT有什么用
- 1.3 JWT的组成
- 1.3.1 Header
- 1.3.2 Payload
- 1.3.3 Signature
- 2 JWT使用
- 2.1 JWT基本使用
- 2.2 SpringBoot+JWT
- 最后
前言
2023-8-31 15:56:24
公开发布于
2024-5-22 00:10:39
推荐
【JWT】袁庭新老师SpringBoot+JWT快速上手1小时轻松搞定JWT
JWT教程
学习目标
- JWT基本概念
- JWT基本使用
- SpringBoot中使用JWT
1 JWT概述
1.1什么是JWT
JSoN web Token,简称JWT。通过数字签名的方式,以JSON对象为载体,在不同的服务终端之间安全的传输信息。
1.2JWT有什么用
JWT通常用于Web应用程序中的身份验证和授权目的。一旦用户登录,后续每个请求都将包含JWT,系统在每次处理用户请求之前,都要先进行JWT安全校验,通过之后再进行处理。
1.3 JWT的组成
JWT由Header、Playload、Signature三部分组成,由.拼接。令牌最终的格式像这样: abc.def.xyz。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM0NzQ2NTMsImp0aSI6ImZkYTBiMjQzLTk4NTAtNDlkYi1iNDMyLWJmMjliYWNiZDVkNyJ9.
mJQUSwod8aV5qmWqLk_yZa8BMTKru8T3BnHlxp53pM4
1.3.1 Header
Header-标头。通常由两部分组成∶令牌的类型(WT)和所使用的签名算法(如HMAC、SHA256或RSA),经过Base64 Url编码后形成JWT的第一部分。
1.3.2 Payload
playload-有效负载。存放用户自定义的信息,通常会把用户信息和令牌到期时间放在这里,同样是一个JSON对象,里面的key和value可随意设置,经过Base64 Url编码后形成JWT的第二部分,由于部分是没有加密的,建议只存放一些非敏感信息。
{
"sub" : "1234567890",
"name" : "john" ,
"admin" : true
}
1.3.3 Signature
Signature-签名。使用标头的算法和私钥对第一部分和第二部分进行加密,通过Base64 url编码后形成JWT的第三部分
var encodeString = base64UrlEncode ( header) + "." + base64UrlEncode( payload) ;
var signature = HMACSHA256 (encodestring,secret ) ;
2 JWT使用
2.1 JWT基本使用
1.使用IDEA创建一个【Spring Initialize】类型的项目名称为【springboot_jwt】的工程。
2.在项目的pom.xml配置文件中添加JWT相关依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.15</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.jsss</groupId>
<artifactId>sptingboot_jwt</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>sptingboot_jwt</name>
<description>sptingboot_jwt</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>compile</scope>
</dependency>
<!-- JWT依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- JWT相关依赖, jdk1.8以上版本还需引入以下依赖-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
**3.创建一个测试类JwtTests **
package com.jsss.sptingboot_jwt.test;
import io.jsonwebtoken.*;
import org.junit.Test;
import java.util.Date;
import java.util.UUID;
public class JwtTests {
private long time = 1000 * 60 * 60 * 1;
private String sign = "admin";
//创建JWT
@Test
public void createJwt() {
//创建一个JwtBuilder对象
JwtBuilder jwtBuilder = Jwts.builder();
//jwtToken abc.def.xyz
String jwtToken = jwtBuilder
//Header:头部
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//Payload:载荷
.claim("username", "tom")
.claim("role", "admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis() + time))//Token的过期时间
.setId(UUID.randomUUID().toString())//id字段
//Signature:签名
.signWith(SignatureAlgorithm.HS256, sign)//设置加密算法和签名
//使用"."连接成一个完整的字符串
.compact();
//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM0NzQ2NTMsImp0aSI6ImZkYTBiMjQzLTk4NTAtNDlkYi1iNDMyLWJmMjliYWNiZDVkNyJ9.mJQUSwod8aV5qmWqLk_yZa8BMTKru8T3BnHlxp53pM4
System.out.println(jwtToken);
}
//验证JWT
@Test
public void checkJwt() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM0NzQ2NTMsImp0aSI6ImZkYTBiMjQzLTk4NTAtNDlkYi1iNDMyLWJmMjliYWNiZDVkNyJ9.mJQUSwod8aV5qmWqLk_yZa8BMTKru8T3BnHlxp53pM4";
boolean result = Jwts.parser().isSigned(token);
System.out.println(result);
}
//解析JWT
@Test
public void parseJwt() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM0NzQ2NTMsImp0aSI6ImZkYTBiMjQzLTk4NTAtNDlkYi1iNDMyLWJmMjliYWNiZDVkNyJ9.mJQUSwod8aV5qmWqLk_yZa8BMTKru8T3BnHlxp53pM4";
JwtParser jwtParser = Jwts.parser();//获取JWT的解析对象
//类似于Map集合
Jws<Claims> claimsJws = jwtParser.setSigningKey(sign).parseClaimsJws(token);//将JWT转化为一个Key-value,通过key来获取对应的value
//获取Jws对象中的数据:get(key)表示根据key来获取value
Claims claims=claimsJws.getBody();//存储的是用户保存的数据
System.out.println(claims.get("username"));
System.out.println(claims.get("role"));
System.out.println(claims.getId());
System.out.println(claims.getSubject());
System.out.println(claims.getExpiration());
}
}
2.2 SpringBoot+JWT
1.创建一个User类
package com.jsss.sptingboot_jwt.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
private String username;
private String password;
private String token;//token字符串
}
2.创建一个JWTUtil工具类
package com.jsss.sptingboot_jwt.utils;
import io.jsonwebtoken.*;
import java.util.Date;
import java.util.UUID;
/**
* JWT工具类
*/
public class JwtUtil {
private static long time = 1000 * 30;
private static String sign = "admin";
public static String createToken() {
//创建一个JwtBuilder对象
JwtBuilder jwtBuilder = Jwts.builder();
//jwtToken abc.def.xyz
String jwtToken = jwtBuilder
//Header:头部
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
//Payload:载荷
.claim("username", "tom")
.claim("role", "admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis() + time))//Token的过期时间
.setId(UUID.randomUUID().toString())//id字段
//Signature:签名
.signWith(SignatureAlgorithm.HS256, sign)//设置加密算法和签名
//使用"."连接成一个完整的字符串
.compact();
return jwtToken;
}
//验证token是否过期的方法
public static boolean checkToken(String token) {
if (token == null || token == "") {
return false;//false表示过期
}
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(sign).parseClaimsJws(token);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}
3.创建一个UserController类
package com.jsss.sptingboot_jwt.controller;
import com.jsss.sptingboot_jwt.domain.User;
import com.jsss.sptingboot_jwt.utils.JwtUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class UserController {
//http://localhost:8080/login?username=tom&password=123456
@GetMapping("login")
public User login(User user){
String username="tom";
String password="123456";
if (username.equals(user.getUsername())&&password.equals(user.getPassword())){
//创建Token: token保存到user对象中
user.setToken(JwtUtil.createToken());
return user;
}
return null;
}
/*
//http://localhost:8080/check_token?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM0NzM2OTIsImp0aSI6Ijk0ZTZiNWRmLTE0NGYtNDA0Mi04OTBkLTA2ZTEwYjIyOWQ4OSJ9.zqPOTa0GHxV0S9Uj2JY9KRfUhsDPk0JJffu6VENJ8fY
@GetMapping("check_token")
public boolean checkToken(String token){
return JwtUtil.checkToken(token);
}
*/
//http://localhost:8080/check_token
@GetMapping("check_token")
public boolean checkToken(HttpServletRequest request){
String token=request.getHeader("token");//key -> token
return JwtUtil.checkToken(token);
}
}
4.跨域配置
package com.jsss.sptingboot_jwt.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
/**
* addMapping("/**"):配置可以被跨域的路径,可以任意配置,可以具体到直接请求路径
* allowedOrigins("*"):允许所有的请求域名访问我们的跨域资源,可以固定单条或者多条内容,如"http://www.yx.com",只有该域名可以访问我们的跨域资源
* allowedHeaders("*"):允许所有的请求header访问,可以定义设置任意请求头信息
* al1owedMethods():允许所有的请求方法访问该跨域资源服努器,如GET、POST、DELETE、PUT、OPTIONS、HEAD等
* maxAge(3600):配置客户端可以缓存pre-flight请求的响应的时间(秒)。默认设置为1800秒(30分钟)
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("**")
.allowedHeaders("*")
.allowedMethods("GET","POST","DELETE","PUT","OPTIONS","HEAD")
.maxAge(3600);
}
}
5.拦截器实现Token验证
package com.jsss.sptingboot_jwt.interceptor;
import com.jsss.sptingboot_jwt.utils.JwtUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class TokenInterceptor implements HandlerInterceptor {
//在请求处理方法被调用之前被调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token=request.getHeader("token");//必须把token放到请求头Header
if (!JwtUtil.checkToken(token)){//验证码失败
return false;
}
return true;
}
}
最后
我们都有光明的未来
祝大家考研上岸
祝大家工作顺利
祝大家得偿所愿
祝大家如愿以偿
点赞收藏关注哦