jwt的了解和使用以及大致代码分析

这篇具有很好参考价值的文章主要介绍了jwt的了解和使用以及大致代码分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

jwt简介

以下介绍来自官网(https://jwt.io/)
SON Web 令牌 (JWT) 是一种开放标准 (RFC 7519),它定义了一种紧凑且独立的方式,用于在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任,因为它是经过数字签名的。JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名**(来自官网)**。

尽管 JWT 可以加密以提供各方之间的保密性,但我们将专注于签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌则向其他方隐藏这些声明。当使用公钥/私钥对对令牌进行签名时,签名还证明只有持有私钥的一方才是签名的一方**(来自官网)**。

使用场景

  • 授权:这是使用 JWT 的最常见方案。用户登录后,每个后续请求都将包含 JWT,允许用户访问使用该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小,并且能够跨不同域轻松使用**(来自官网)**。

  • 信息交换:JSON Web 令牌是在各方之间安全传输信息的好方法。由于 JWT 可以签名(例如,使用公钥/私钥对),因此您可以确定发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改**(来自官网)**)。

jwt的组成结构

  • Header
  • Payload
  • Signature
    因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz

Header

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

{
  "alg": "HS256",
  "typ": "JWT"
}

然后,此JSON被Base64Url编码以形成JWT的第一部

Payload(有效载荷)

令牌的第二部分是有效负载,其中包含声明。声明是有关实体(通常是用户)和其他数据的语句。
有三种类型的声明:已注册、公共和私人声明。
已注册声明:这些是一组预定义的声明,这些声明不是必需的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:iss(发行人),exp(到期时间),sub(主题),aud(受众)等。

请注意,声明名称只有三个字符长,因为 JWT 应该是紧凑的。

公共声明:这些可以由使用 JWT 的人随意定义。但为了避免冲突,它们应该在 IANA JSON Web 令牌注册表中定义,或者定义为包含抗冲突命名空间的 URI。

专用声明:这些是创建的自定义声明,用于在同意使用它们的各方之间共享信息,既不是注册声明也不是公共声明。

示例有效负载可以是:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

sub是预定义的声明,name,admin则是自己随便添加的一些定义
然后对有效负载进行 Base64Url 编码以形成 JSON Web 令牌的第二部分。

请注意,对于签名令牌,此信息虽然受到篡改保护,但任何人都可以读取。不要将机密信息放在 JWT 的有效负载或标头元素中,除非它已加密。

签名

要创建签名部分,您必须获取编码的标头、编码的有效负载、机密、标头中指定的算法并对其进行签名。

例如,如果要使用 HMAC SHA256 算法,将按以下方式创建签名:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

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

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

使用java-jwt来生成和解析token

导入maven依赖

<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.4.0</version>
		</dependency>

这附上一段我之前写的代码

    public String getToken(Users user) {
        String token="";
        // 2*24*3600 * 1000
        token= JWT.create()
                .withExpiresAt(new Date(System.currentTimeMillis() + (2*24*3600*1000)))
                .withAudience(user.getEmployeeId())// 将 login_user 保存到 token 里面
                .sign(Algorithm.HMAC256(DigestUtils.md5Hex(user.getEmployeePassword()+ Constants.MD5PRIVATEKEY)));// 以 password 作为 token 的密钥
        return token;
    }

这是上面引入的依赖提供的方法
首先是 JWT.create(),create方法去调用了JWTCreator的init方法

public static JWTCreator.Builder create() {
        return JWTCreator.init();
    }

然后init方法又new了一个自己的内部类,内部类给头部(headerClaims)和载荷(payloadClaims)声明了引用地址

    /**
     * Initialize a JWTCreator instance.
     *
     * @return a JWTCreator.Builder instance to configure.
     */
    static JWTCreator.Builder init() {
        return new Builder();
    }

    /**
     * The Builder class holds the Claims that defines the JWT to be created.
     */
    public static class Builder {
        private final Map<String, Object> payloadClaims;
        private Map<String, Object> headerClaims;

        Builder() {
            this.payloadClaims = new HashMap<>();
            this.headerClaims = new HashMap<>();
        }

紧接着withExpiresAt()和withAudience()实际上就是给载荷里预定义的声明赋值,withExpiresAt()就是给exp赋值,withAudience()就是给aud赋值

     /**
         * Add a specific Audience ("aud") claim to the Payload.
         *
         * @param audience the Audience value.
         * @return this same Builder instance.
         */
        public Builder withAudience(String... audience) {
            addClaim(PublicClaims.AUDIENCE, audience);
            return this;
        }

        /**
         * Add a specific Expires At ("exp") claim to the Payload.
         *
         * @param expiresAt the Expires At value.
         * @return this same Builder instance.
         */
        public Builder withExpiresAt(Date expiresAt) {
            addClaim(PublicClaims.EXPIRES_AT, expiresAt);
            return this;
        }

它们都调用了addClaim方法,可以看到就是在载荷的那个map中添加key和value

 private void addClaim(String name, Object value) {
            if (value == null) {
                payloadClaims.remove(name);
                return;
            }
            payloadClaims.put(name, value);
        }

前面说过也可以自定义声明添加到载荷这部分,这里也提供了多个方法,这里展示两个

   /**
         * Add a custom Claim value.
         *
         * @param name  the Claim's name.
         * @param value the Claim's value.
         * @return this same Builder instance.
         * @throws IllegalArgumentException if the name is null.
         */
        public Builder withClaim(String name, Boolean value) throws IllegalArgumentException {
            assertNonNull(name);
            addClaim(name, value);
            return this;
        }

        /**
         * Add a custom Claim value.
         *
         * @param name  the Claim's name.
         * @param value the Claim's value.
         * @return this same Builder instance.
         * @throws IllegalArgumentException if the name is null.
         */
        public Builder withClaim(String name, Integer value) throws IllegalArgumentException {
            assertNonNull(name);
            addClaim(name, value);
            return this;
        }

然后是sign()方法,这里这里传入了一个我们指明秘钥的算法,headerClaims.put方法给头部添加了令牌的类型(即 JWT)和正在使用的签名算法

/**
         * Creates a new JWT and signs is with the given algorithm
         *
         * @param algorithm used to sign the JWT
         * @return a new JWT token
         * @throws IllegalArgumentException if the provided algorithm is null.
         * @throws JWTCreationException     if the claims could not be converted to a valid JSON or there was a problem with the signing key.
         */
        public String sign(Algorithm algorithm) throws IllegalArgumentException, JWTCreationException {
            if (algorithm == null) {
                throw new IllegalArgumentException("The Algorithm cannot be null.");
            }
            headerClaims.put(PublicClaims.ALGORITHM, algorithm.getName());
            headerClaims.put(PublicClaims.TYPE, "JWT");
            String signingKeyId = algorithm.getSigningKeyId();
            if (signingKeyId != null) {
                withKeyId(signingKeyId);
            }
            return new JWTCreator(algorithm, headerClaims, payloadClaims).sign();
        }

然后new 了一个JWTCreator对象

 private JWTCreator(Algorithm algorithm, Map<String, Object> headerClaims, Map<String, Object> payloadClaims) throws JWTCreationException {
        this.algorithm = algorithm;
        try {
            ObjectMapper mapper = new ObjectMapper();
            SimpleModule module = new SimpleModule();
            module.addSerializer(ClaimsHolder.class, new PayloadSerializer());
            mapper.registerModule(module);
            mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
            headerJson = mapper.writeValueAsString(headerClaims);
            payloadJson = mapper.writeValueAsString(new ClaimsHolder(payloadClaims));
        } catch (JsonProcessingException e) {
            throw new JWTCreationException("Some of the Claims couldn't be converted to a valid JSON format.", e);
        }
    }

这里可以看到这两句代码,把头部这个map和载荷这个map都转换成了json串

  headerJson = mapper.writeValueAsString(headerClaims);
  payloadJson = mapper.writeValueAsString(new ClaimsHolder(payloadClaims));

然后返回,在new一个JWTCreator对象后又调用了这个对象的sign()方法

 private String sign() throws SignatureGenerationException {
        String header = Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));
        String payload = Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));
        String content = String.format("%s.%s", header, payload);

        byte[] signatureBytes = algorithm.sign(content.getBytes(StandardCharsets.UTF_8));
        String signature = Base64.encodeBase64URLSafeString((signatureBytes));

        return String.format("%s.%s", content, signature);
    }

可以看到首先对header也就是头部做了base64编码,然后对载荷 payload也做了base64编码

String header = Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8));
String payload = Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8));

然后使用小数点连接

String content = String.format("%s.%s", header, payload);

然后使用算法对连接后的头部和载荷进行签名,最后形成签名

byte[] signatureBytes = algorithm.sign(content.getBytes(StandardCharsets.UTF_8));

然后用base64对签名进行编码,再把编码后的签名和前面的头部,载荷连接起来文章来源地址https://www.toymoban.com/news/detail-726843.html

String signature = Base64.encodeBase64URLSafeString((signatureBytes));

return String.format("%s.%s", content, signature);

到了这里,关于jwt的了解和使用以及大致代码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Jwt(Json web token)——使用token的权限验证方法 & 用户+角色+权限表设计 & SpringBoot项目应用

    1.认证鉴权服务,注册中心,认证中心,鉴权中心; 2.用户,角色,权限表设计,数据库视图的使用; 3.项目中的应用,使用自定义注解+拦截器; 4.枚举类型的json化, @JsonFormat(shape = JsonFormat.Shape.OBJECT) @Getter https://gitee.com/pet365/springboot-privs-token 用户和权限之间关系(多对多

    2024年02月14日
    浏览(46)
  • 操作过滤器—MVC中使用操作过滤器实现JWT权限认证

    上一篇文章分享了授权过滤器实现JWT进行鉴权,文章链接:授权过滤器—MVC中使用授权过滤器实现JWT权限认证,接下来将用操作过滤器实现昨天的JWT鉴权。 ​ 与授权过滤器大部分一样,只是执行的时机和继承的接口有所不同。操作过滤器是在Action执行的前和后进行调用执行

    2024年02月13日
    浏览(32)
  • 如何使用 NestJS 集成 Passort 和 JWT Token 实现 HTTP 接口的权限管理

    💡 如果你不希望其他人可以随意进出你的房子,那么你需要给你的房子上个锁。 开发一个接口很容易,开发一个具有安全性的接口却不容易。成熟的后端服务项目最注重的一点就是如何保护系统的数据安全,不能让用户无脑的访问操作所有的数据,这是不合理更是极度危险

    2024年01月22日
    浏览(35)
  • 使用WebApi+Vue3从0到1搭建《权限管理系统》:二、搭建JWT系统鉴权

    视频地址:【WebApi+Vue3从0到1搭建《权限管理系统》系列视频:搭建JWT系统鉴权-哔哩哔哩】 https://b23.tv/R6cOcDO qq群:801913255 一、在appsettings.json中设置鉴权属性 二、新建模型 添加模型JwtSettingModel其中字段和appsettings.json中的字段一样,如下 三、新建解析appsettings.json节点的帮助类

    2024年04月22日
    浏览(29)
  • 瑞数 6 代逆向纯算法大致流程分析

    aHR0cHM6Ly93d3cudXJidGl4LmhrLw== 第一次请求响应 202,响应内容中有一段 JS 代码会请求一个 JS 文件,Cookie 生成的核心代码由这个文件中的代码生成,并通过 eval 执行。 Cc2838679FS 55tgE9EWzzOxyDeuMRQ8rVOKqNZG4W9awmtpvnl1jpeviOqlzHzrnraSnPN8F2w6OqgnjY6ueb1NAN2kE03ryDG Cc2838679FT 6RifvpbsLR03qqqDtteJ.XqqugbVLuRivnvi

    2024年02月08日
    浏览(39)
  • linux elasticsearch安装以及设置安全权限账号跟密码

    1.下载安装 1.1 官网下载地址 : https://www.elastic.co/cn/downloads/elasticsearch 选择自己需要的版本下载,然后上传到Linux 也可以用Linux命令行,执行wget下载: 下载需要版本 执行解压缩命令: tar -zxvf es安装包 1.2 解决es强依赖jdk问题 由于es和jdk是一个强依赖的关系,所以当我们在新版

    2024年02月15日
    浏览(56)
  • 【微信小程序】 权限接口梳理以及代码实现

    ​ 官方权限说明   部分接口需要经过用户授权统一才能调用。我们把这些接口按使用范围分成多个scope,用户选择对scope进行授权,当授权给一个scope之后,其对应的所有接口都可以直接使用。 此类接口调用时: 如果用户未接受或拒绝过此权限,会弹窗询问用户,用户点击

    2024年02月04日
    浏览(30)
  • RabbitMQ篇——一篇文章带你入门RabbitMQ,了解RabbitMQ的角色分类权限、AMQP协议以及设计第一个RabbitMQ程序!

    RabbitMQ是一个开源的消息代理和消息队列系统,采用AMQP(Advanced Message Queuing Protocol)协议。它被设计用于在分布式系统中进行高效,可靠和可扩展的消息传递。 RabbitMQ基本概念: Producer(生产者):生产者负责发布消息到消息队列中。 Consumer(消费者):消费者从消息队列中

    2024年01月16日
    浏览(44)
  • 红黑树的了解以及代码实现

            红黑树是在二叉搜索树的基础上 添加颜色 , 通过对任何一条路径的颜色的限制,确保红黑树的任何一条路径不会超过其他路径的两倍 ,是一棵近似平衡的树。         红黑树的节点不是红色就是黑色,其节点的排列除了需要按二插搜索树的规则来插入之外,还

    2024年02月03日
    浏览(30)
  • Spring Security安全登录的调用过程以及获取权限的调用过程

    (0)权限授理 首先调用SecurityConfig.java中的config函数将jwtAuthenticationTokenFilter过滤器放在UsernamePasswordAuthenticationFilter之前 (1)首先运行JwtAuthenticationTokenFilter extends OncePerRequestFilter中的doFilterInternal函数 这里由于没有获取到token,因此调用!StringUtils.hasText(token),这里使用 继续运行其他

    2024年02月09日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包