go引入jwt鉴权 | 青训营

86 阅读2分钟

一.JWT介绍

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

1.JWT数据结构

实际的JWT是由三部分组成的,三部分依次如下所示:

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

写成一行就是Header.Payload.Signature

2.Header

Header 部分是一个 JSON 对象,用来描述 JWT 的元数据,通常是下面的样子

image.png

alg属性表示签名的算法(algorithm),默认是HMAC SHA256;typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。

3.Payload

Payload 部分其实也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,分别如下所示:

iss (issuer):签发人

exp (expiration time):过期时间

sub (subject):主题

aud (audience):受众

nbf (Not Before):生效时间

iat (Issued At):签发时间

jti (JWT ID):编号

4.Signature

Signature 部分是对前两部分的签名,防止数据篡改。

首先,我们需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

image.png

5.Base64URL

最后是最关键的东西,JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.xxxxx.com/?token=xxx)。Base64 有三个字符+,/和=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-,/替换成_ ,这就需要用到 Base64URL 算法。

二.使用JWT

1.引入jwt

go install "github.com/golang-jwt/jwt/v4"

2.生成token

type MyClaims struct { Phone string json:"phone"`` jwt.RegisteredClaims
} var MySecret = []byte("密码") 生成token // 根据自己的需求来替换 func MakeToken(UserName string) (tokenString string, err error) { claim := MyClaims{ UserName: userName, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(3 * time.Hour * time.Duration(1))), // 过期时间3小时 IssuedAt: jwt.NewNumericDate(time.Now()), // 签发时间 NotBefore: jwt.NewNumericDate(time.Now()), // 生效时间 }} token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) // 使用HS256算法 tokenString, err = token.SignedString(MySecret) return tokenString, err }

3.解析token

func Secret() jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { return []byte("密码"), nil // 这是我的secret } }

func ParseToken(tokenss string) (*MyClaims, error) { token, err := jwt.ParseWithClaims(tokenss, &MyClaims{}, Secret()) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, errors.New("that's not even a token") } else if ve.Errors&jwt.ValidationErrorExpired != 0 { return nil, errors.New("token is expired") } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, errors.New("token not active yet") } else { return nil, errors.New("couldn't handle this token") } } } if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { return claims, nil } return nil, errors.New("couldn't handle this token") }

自此完成基本操作......