JWT的应用

JWT的生成与使用,在golang中的应用

什么是JWT

jwt,全称JSON Web Token,是一种开放标准(RFC 7519),用于在网络应用环境间安全地传输信息。这些信息可以被验证和信任,因为它们是数字签名的。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

JWT的用途

JWT的主要目的是在各方之间传递声明。声明是对实体(通常是用户)的某些属性的断言,例如身份、访问权限等。这些声明以紧凑的形式编码为一个字符串,非常适合在Web环境中使用,尤其是在HTTP头部中作为承载令牌(Bearer Token)。

在我们设计网站时,经常应用jwt用来鉴权,判断用户的登录状态,今天主要介绍利用GitHub - golang-jwt/jwt: Go implementation of JSON Web Tokens (JWT).包,实现Go语言下的jwt生成和解析。

例如,在中间件中,我们可以通过设置过期日期,然后解析jwt,来判断用户的登录状态。

安装

1
go get -u github.com/golang-jwt/jwt/v5

生成

本文介绍如何编码和解码一个自定义结构体

为模拟真实使用环境,我们首先定义一个结构体类型,如下,包含用户名和id字段

1
2
3
4
5
type UserJWTModel struct {
	ID       int
	Username string
	jwt.RegisteredClaims
}

jwt.RegisteredClaims里包含了一些jwt约定好的字段,比如ExpiresAt,可以约定jwt的过期时间。以及其他字段,下面我们仅仅用到了ExpiresAt,更详细的请查阅jwt的文档。

然后新建一个token,填入数据

1
2
3
4
5
6
7
token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserJWTModel{
		1,
		"dinglz",
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 10)),
		},
	})

这里约定好过期时间是十分钟后

然后用一个password生成jwt

1
2
t, _ := token.SignedString([]byte("password"))
fmt.Println(t)

完整示例

 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
package main

import (
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

type UserJWTModel struct {
	ID       int
	Username string
	jwt.RegisteredClaims
}

func main() {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserJWTModel{
		1,
		"dinglz",
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 10)),
		},
	})
	t, _ := token.SignedString([]byte("password"))
	fmt.Println(t)
}

解析

1
2
3
4
5
6
tokenAfter, e := jwt.ParseWithClaims(t, &UserJWTModel{}, func(t *jwt.Token) (interface{}, error) {
		return []byte("password"), nil
	})
	if e != nil {
		panic(e.Error())
	}

t是我们上面生成的字符串,然后选择解析的模型,最后在传回加密时的密码,即可得到解析后的token,如果过期或者密码错误等会使e!=nil,因此可以通过是否错误来判断登录是否过期。

取回我们解析后的结构体

1
cliamAfter := tokenAfter.Claims.(*UserJWTModel)

经验证,我们取出了传进去的数据。

完整示例

 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
package main

import (
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v5"
)

type UserJWTModel struct {
	ID       int
	Username string
	jwt.RegisteredClaims
}

func main() {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserJWTModel{
		1,
		"dinglz",
		jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 10)),
		},
	})
	t, _ := token.SignedString([]byte("password"))
	fmt.Println(t)

	tokenAfter, e := jwt.ParseWithClaims(t, &UserJWTModel{}, func(t *jwt.Token) (interface{}, error) {
		return []byte("password"), nil
	})
	if e != nil {
		panic(e.Error())
	}

	cliamAfter := tokenAfter.Claims.(*UserJWTModel)
	fmt.Println(cliamAfter)
}

实际应用

比如我们可以在登录后往cookie中存入jwt,然后在需要鉴权的地方用中间件解析他,如果能成功则不用验证其他内容,因为在某种程度上我们可以认为jwt不会被伪造。

code

Last updated on Nov 29, 2024 02:00 UTC
copyright © dinglz
Built with Hugo
Theme Stack designed by Jimmy