dinglz 发表于 2022-2-6 17:08:25

浅谈jwt 及 Go语言实现

JWT 全称 JSON Web Token 即 JSON Web 令牌

那么,什么是jwt:

JSON Web Token (JWT) 是一个开放标准 (RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息作为 JSON 对象。此信息可以验证和信任,因为它是数字签名的。 JWT 可以使用密钥(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。


static/image/hrline/2.gif


什么时候应该使用 JSON Web Tokens?

授权:这是使用 JWT 最常见的场景。用户登录后,每个后续请求都将包含 JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销很小并且能够在不同的域中轻松使用。

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


static/image/hrline/2.gif


JSON Web Token 结构是什么?

JSON Web Tokens 由三部分组成,由点 (.) 分隔,它们是:标题、有效载荷(payload)、签名

因此,JWT 通常如下所示。
xxxxx.yyyyy.zzzzz

标头通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的陈述。
签名用于验证消息在此过程中没有被更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者就是它所说的那个人。


static/image/hrline/2.gif


为什么我们应该使用 JSON Web Tokens?

由于 JSON 不像 XML 那样冗长,因此在对其进行编码时,它的大小也更小,这使得 JWT 比 SAML 更紧凑。这使得 JWT 成为在 HTML 和 HTTP 环境中传递的不错选择。
安全方面,SWT 只能通过使用 HMAC 算法的共享密钥进行对称签名。但是,JWT 和 SAML 令牌可以使用 X.509 证书形式的公钥/私钥对进行签名。与签署 JSON 的简单性相比,使用 XML 数字签名签署 XML 而不引入隐蔽的安全漏洞是非常困难的。
JSON 解析器在大多数编程语言中都很常见,因为它们直接映射到对象。相反,XML 没有自然的文档到对象映射。这使得使用 JWT 比使用 SAML 断言更容易。
关于使用,JWT 用于 Internet 规模。这突出了 JSON Web 令牌在多个平台(尤其是移动平台)上客户端处理的便利性。


static/image/hrline/2.gif

static/image/hrline/2.gif

Go语言实现

由于其适用于http,拿go语言举例子再好不过了,下面的例子不涉及http层面,而涉及本地的构造和解析。

为了避开复杂的编码层面,我们将使用这个开源的jwt库:
https://github.com/golang-jwt/jwt

整个例子分为三个部分,首先,构造一个jwt,如图



第二个部分,负责解析



最后,在主函数生成并解析。



输出结果如图所示




static/image/hrline/2.gif


完整示例代码如下

package main

import (
        "fmt"
        "github.com/golang-jwt/jwt"
        "time"
)

func main() {
        res := Create()
        Parse(res)
}

//构造函数
func Create() string {
        //新建一个jwt,nbf标识时间,如果时间属于未来时间或不合法时间,将无法取出数据
        token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{
                "nbf":   time.Now().Unix(),
                "test":"消息",
                "test2": "消息2",
        })
        //对该jwt签名,这里的dinglz是秘钥
        tokenString, err := token.SignedString([]byte("dinglz"))
        //将最终的结果数据
        fmt.Println(tokenString, err)
        return tokenString
}

func Parse(tokenString string) {
        //解析
        token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
                if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                        return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
                        //判断是不是已知加密方式
                }
                //返回秘钥
                return []byte("dinglz"), nil
        })
        //判断jwt是否可用
        if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
                //取出结果
                fmt.Println(claims["nbf"], claims["test"], claims["test2"]) //test、test2是在构建时写进的键
        } else {
                fmt.Println(err)
        }

}

wawdgj 发表于 2022-2-7 21:49:40

感谢楼主的分享,听楼主一席话,胜读十年书
页: [1]
查看完整版本: 浅谈jwt 及 Go语言实现