jwt简介和在go中的简单使用

什么是 JSON Web 令牌?

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

尽管 JWT 可以加密以在各方之间提供机密性,但我们将重点介绍签名 令牌。签名令牌可以验证其中包含的声明的完整性 ,而加密令牌则对其他方隐藏这些声明。当使用公钥/私钥对令牌进行签名时,签名还会证明只有持有私钥的一方是签署私钥的一方。

何时应使用 JSON Web 令牌?

以下是 JSON Web 令牌有用的一些情况:

  • 授权:这是使用 JWT 的最常见场景。用户登录后,每个后续请求都将包含 JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用 JWT 的一项功能,因为它的开销小,并且能够轻松地跨不同域使用。
  • 信息交换:JSON Web 令牌是在各方之间安全地传输信息的好方法。由于 JWT 可以签名(例如,使用公钥/私钥对),因此您可以确保发件人是他们所声称的身份。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改。

什么是 JSON Web 令牌结构?

在其紧凑形式中,JSON Web 令牌由三个部分组成,由点 () 分隔,它们是:.

  • 页眉
  • 有效载荷
  • 签名

因此,JWT 通常如下所示。

xxxxx.yyyyy.zzzzz

让我们分解不同的部分。

页眉

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

例如:

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

然后,此 JSON 经过 Base64Url 编码以形成 JWT 的第一部分。

有效载荷

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

  • 已注册的声明:这些是一组预定义的声明,不是强制性的,但建议使用,以提供一组有用的、可互操作的声明。其中一些是:iss (颁发者)、exp (过期时间)、sub (主题)、aud (受众)等。

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

  • Public claims:这些声明可以由使用 JWT 的用户随意定义。但为避免冲突,应在 IANA JSON Web 令牌注册表中定义它们,或将其定义为包含抗冲突命名空间的 URI。

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

一个示例有效负载可以是:

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

然后,对有效负载进行 Base64Url 编码,以形成 JSON Web 令牌的第二部分。

请注意,对于签名令牌,此信息虽然可以防止篡改,但任何人都可以读取。除非 JWT 已加密,否则不要将机密信息放在 JWT 的 payload 或 header 元素中。

签名

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

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

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

签名用于验证消息在整个过程中没有被更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发件人是否是它所声称的身份。

把所有的东西放在一起

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

下面显示了一个 JWT,该 JWT 对之前的标头和有效负载进行了编码,并使用密钥进行了签名。

在go中的简单使用

下载依赖jwt官方库

go 复制代码
go get -u github.com/golang-jwt/jwt/v5

创建

创建一个携带用户基本信息的token

go 复制代码
// JwtPayLoad jwt中payload数据
type JwtPayLoad struct {
  UserID   uint   `json:"user_id"`
  Username string `json:"username"` // 用户名
  Role     int    `json:"role"`     // 权限  
}

type CustomClaims struct {
  JwtPayLoad
  jwt.RegisteredClaims
}

// GenToken 创建 Token
func GenToken(user JwtPayLoad, accessSecret string, expires int64) (string, error) {
  claim := CustomClaims{
    JwtPayLoad: user,
    RegisteredClaims: jwt.RegisteredClaims{
      ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * time.Duration(expires))),
    },
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
  return token.SignedString([]byte(accessSecret))//自定义秘钥,[]byte类型
}

RegisteredClaims

RegisteredClaims是一个结构体,可以根据需求选择填写生成的token内容

go 复制代码
type RegisteredClaims struct {
    // Issuer (iss) - 签发者
	// the `iss` (Issuer) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1
	Issuer string `json:"iss,omitempty"`

    // Subject (sub) - 主题/主体
	// the `sub` (Subject) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.2
	Subject string `json:"sub,omitempty"`

    // Audience (aud) - 接收方
	// the `aud` (Audience) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3
	Audience ClaimStrings `json:"aud,omitempty"`

    // ExpiresAt (exp) - 过期时间,设置为当前时间之后24小时
	// the `exp` (Expiration Time) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4
	ExpiresAt *NumericDate `json:"exp,omitempty"`

    // NotBefore (nbf) - 生效时间,设置为当前时间
	// the `nbf` (Not Before) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.5
	NotBefore *NumericDate `json:"nbf,omitempty"`

    // IssuedAt (iat) - 签发时间
	// the `iat` (Issued At) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6
	IssuedAt *NumericDate `json:"iat,omitempty"`

    // ID (jti) - JWT ID,唯一标识符
	// the `jti` (JWT ID) claim. See https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7
	ID string `json:"jti,omitempty"`
}

验证

go 复制代码
// ParseToken 解析 token
func ParseToken(tokenStr string, accessSecret string, expires int64) (*CustomClaims, error) {

  token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    return []byte(accessSecret), nil
  })
  if err != nil {
    return nil, err
  }
  if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
    return claims, nil
  }
  return nil, errors.New("invalid token")
}
相关推荐
迷雾漫步者34 分钟前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-1 小时前
验证码机制
前端·后端
xlsw_1 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹2 小时前
基于java的改良版超级玛丽小游戏
java
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭2 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫3 小时前
泛型(2)
java
超爱吃士力架3 小时前
邀请逻辑
java·linux·后端
南宫生3 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论