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使用

JWT教程【JWT】_spring

2.1 JWT基本使用

1.使用IDEA创建一个【Spring Initialize】类型的项目名称为【springboot_jwt】的工程。

JWT教程【JWT】_java_02

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

JWT教程【JWT】_spring_03

JWT教程【JWT】_java_04

最后

我们都有光明的未来

祝大家考研上岸
祝大家工作顺利
祝大家得偿所愿
祝大家如愿以偿
点赞收藏关注哦