• springboot 集成JWT实现token验证


    JWT介绍

    • 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于将信息作为 JSON 对象在各方之间安全地传输。该信息可以进行验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
    • JWT只是缩写,全拼则是 JSON Web Tokens ,是目前流行的跨域认证解决方案,一种基于JSON的、用于在网络上声明某种主张的令牌(token)。

    JWT 优缺点

    • 优点
      • 支持跨域访问
      • 基于 token 的认证方式相比传统的 session 认证方式更节约服务器资源
      • 无状态
      • 更适用CDN
      • 更适用于移动端
      • 无需考虑CSRF
    • 缺点
      • 由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
      • JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。

    JWT 结构

    JWT 是由三段字符串和两个 . 组成,每个字符串和字符串之间没有换行(类似于这样:xxxxxx.yyyyyy.zzzzzz),每个字符串代表了不同的功能,我们将这三个字符串的功能按顺序列出来并讲解:

    标头(header)

    标头通常由两部分组成:令牌的类型和正在使用的签名算法(如 HMAC SHA256 或 RSA)。例如:

    {
    	“alg”: “HS256”,
    	“typ”: “JWT”
    }
    
    • 1
    • 2
    • 3
    • 4

    使用 Base64 URL 算法将该 JSON 对象转换为字符串保存,形成 JWT 的第一部分。

    有效载荷(payload)

    JWT 的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和其他数据的语句。有三种类型的声明:注册声明、公共声明和私人声明。

    • 标准注册声明
      标准注册声明不是强制使用是的,但是我建议使用。它一般包括以下内容:
    iss:#jwt的签发者/发行人;
    
    sub#主题;
    
    aud:#接收方;
    
    exp:#jwt过期时间;
    
    nbf:#jwt生效时间;
    
    iat:#签发时间
    
    jti:#jwt唯一身份标识,可以避免重放攻击
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 公共声明
      可以在公共声明添加任何信息,我们一般会在里面添加用户信息和业务信息,但是不建议添加敏感信息,因为公共声明部分可以在客户端解密。

    • 私有声明
      私有声明是服务器和客户端共同定义的声明,同样这里不建议添加敏感信息。
      以下是有效负载的示例:

    {
    	“sub”: “1234567890”,
    	“name”: “John Doe”,
    	“admin”: true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    签名(Signature)

    要创建签名部分,必须获取编码的标头、编码的有效负载、密钥,通过指定的算法生成哈希,以确保数据不会被篡改。
    例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:

    HMACSHA256( base64UrlEncode(header) + “.” +
    			base64UrlEncode(payload),
    			secret)
    
    • 1
    • 2
    • 3

    签名用于验证消息在此过程中未发生更改。并且,对于使用私钥签名的令牌,它还可以验证 JWT 的发送者是否是它所说的发件人。

    将所有内容放在一起,输出是三个 Base64-URL 字符串,由点分隔,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。

    创建项目集成 JWT 实现 token 验证

    添加依赖

    
    <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.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.7.5version>
            <relativePath/> 
        parent>
        <groupId>com.examplegroupId>
        <artifactId>springboot-jwt-demoartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>springboot-jwt-demoname>
        <description>springboot-jwt-demodescription>
        <properties>
            <java.version>8java.version>
            <jjwt.version>0.11.2jjwt.version>
        properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-configuration-processorartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
    
            
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwt-apiartifactId>
                <version>${jjwt.version}version>
            dependency>
    
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwt-implartifactId>
                <version>${jjwt.version}version>
            dependency>
            <dependency>
                <groupId>io.jsonwebtokengroupId>
                <artifactId>jjwt-jacksonartifactId>
                <version>${jjwt.version}version>
                <scope>runtimescope>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombokgroupId>
                                <artifactId>lombokartifactId>
                            exclude>
                        excludes>
                    configuration>
                plugin>
            plugins>
        build>
    
    project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    添加实体类 LoginUser

    
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    public class LoginUser {
        /**
         * 账户
         */
        private Long accoutNo;
        /**
         * 用户名
         */
        private String userName;
        /**
         * 头像
         */
        private String headImg;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    新建 JWT 工具类 JWTUtil

    
    import com.example.springbootjwtdemo.model.LoginUser;
    import io.jsonwebtoken.security.Keys;
    import lombok.extern.slf4j.Slf4j;
    
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    
    
    import java.nio.charset.StandardCharsets;
    import java.security.Key;
    import java.util.Date;
    import java.util.Objects;
    
    @Slf4j
    public class JWTUtil {
    
        /**
         * token 过期时间 正常是7天
         */
        private static final long EXPIRE = 1000 * 60 * 60 * 24 * 7;
        /**
         * 加密秘钥 UUID.randomUUID().toString().replaceAll("-","") 生成
         */
        private static final String SECRET = "ff9b84d01c0940c6a5723a744d0d66a8";
        /**
         * token前缀
         */
        private static final String TOKEN_PREFIX = "org";
    
        /**
         * subject
         */
        private static final String SUBJECT = "my";
        /**
         * 加密秘钥
         */
        private static final Key key = Keys.hmacShaKeyFor(SECRET.getBytes(StandardCharsets.UTF_8));
        /**
         * 使用系统默认token
         */
    //    private static final Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    
    
        /**
         * 生成token
         *
         * @param loginUser 登录用户
         * @return {@link String}
         */
        public static String geneJsonWebToken(LoginUser loginUser) {
            if (Objects.isNull(loginUser)) {
                throw new NullPointerException("LoginUser对象不能为空");
            }
            String token = Jwts.builder().setSubject(SUBJECT)
                    .claim("accout_no", loginUser.getAccoutNo())
                    .claim("head_img", loginUser.getHeadImg())
                    .claim("user_name", loginUser.getUserName())
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                    .signWith(key, SignatureAlgorithm.HS256).compact();
    
            token = TOKEN_PREFIX + token;
            return token;
        }
    
        /**
         * 检查 token
         *
         * @param token 令牌
         * @return {@link Claims}
         */
        public static Claims checkJWT(String token) {
            try {
                return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody();
            } catch (Exception e) {
                log.info("jwt token解密系统异常:{}", e);
                return null;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    新建控制类 LoginController

    
    import com.example.springbootjwtdemo.model.LoginUser;
    import com.example.springbootjwtdemo.utils.JWTUtil;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    
    @RestController
    @RequestMapping("/user")
    public class LoginController {
    
        @GetMapping("login")
        public String login(LoginUser loginUser) {
    
            // 生成token
            LoginUser userInfo = new LoginUser();
            userInfo.setUserName("展释");
            userInfo.setAccoutNo(123213L);
            userInfo.setHeadImg("");
            return JWTUtil.geneJsonWebToken(loginUser);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    请求结果

    在这里插入图片描述

  • 相关阅读:
    腾讯云产品---mysql 逻辑备份大表以及手动恢复表数据实战
    分享一个403界面给大家
    JAVA互联网一线大厂面试真题自测,顺便看看大牛的通行证
    DHTMLX JavaScript Gantt 8.0.6 Crack
    Java编程实战10:正则表达式匹配
    promise中合并对象的实例方法
    JS代码案例
    JAVA面试总结
    Vue中判断语句和循环语句的基础用法 v-if和v-for的注意事项
    聚观早报|中国制造成世界杯交通主力;特斯拉拟召回32万辆车
  • 原文地址:https://blog.csdn.net/laow1314/article/details/128092789