什么是JWT:
JWT(JSON Web Token)是一种开放标准(RFC 7519),定义了一种紧凑且自包含的方式,用于在各方之间安全地传输信息。JWT通常用于在身份验证和信息交换方面进行安全的传输,例如在用户登录后生成一个JWT作为身份验证凭证,在客户端和服务器之间进行安全的信息交换。
JWT由三部分组成:头部(header)、载荷(payload)和签名(signature)。头部通常包含了令牌的类型和使用的加密算法;载荷包含了要传输的信息,例如用户ID、角色等;签名则是对头部和载荷进行加密后的结果,用于验证令牌的真实性和完整性。
JWT具有自包含性,因此可以在各方之间安全地传输信息,而且由于使用了数字签名,可以保证令牌的真实性和完整性。JWT在Web应用程序中得到广泛应用,例如用于身份验证、单点登录、API访问控制等方面。
JWT的作用:
JWT(JSON Web Token)的作用主要包括以下几个方面:
1. 身份验证:JWT可以作为身份验证的凭证,用于验证用户的身份,确保用户有权访问受保护的资源或执行特定操作。
2. 信息交换:JWT可以在各方之间安全地传输信息,例如在用户登录后生成一个JWT作为身份验证凭证,在客户端和服务器之间进行安全的信息交换。
3. 授权:JWT可以包含用户的角色、权限等信息,用于授权用户对特定资源或操作的访问权限。
4. 单点登录:JWT可以用于实现单点登录(SSO),用户在一个应用程序登录后,可以通过JWT在其他应用程序中进行身份验证,而无需重新输入凭证。
总之,JWT作为一种安全的传输方式,可以在各方之间传递信息并验证信息的真实性和完整性,因此在身份验证、授权和信息交换方面得到广泛应用。
go的JWT
JWT可以分为三部分:
头部:头部通常包含了令牌的类型和使用的加密算法
负载:载荷包含了要传输的信息,例如用户ID、角色、权限
签名: 签名是对头部和载荷进行加密后的结果,用于验证令牌的真实性和完整性
JWT中的七个标准字段:
Issuer(签发人):用于标识JWT的签发者。
Subject(主题):用于标识JWT的主体,即JWT所面向的用户。
Audience(受众):用于标识JWT的接收者。
ExpiresAt(过期时间):用于标识JWT的过期时间,以Unix时间戳表示。
NotBefore(生效时间):用于标识JWT的生效时间,以Unix时间戳表示。
IssuedAt(签发时间):用于标识JWT的签发时间,以Unix时间戳表示。
JWT ID(编号):用于标识JWT的唯一ID。
第一步自定义结构体把信息存入MyClaims中
// 自定义结构体可以把需要的信息存入到jwt中
type MyClaims struct {
UserID uint64
Username string
jwt.StandardClaims //jwt标准声明规范中的七个标准字段
}
///Issuer(签发人):用于标识JWT的签发者。
//Subject(主题):用于标识JWT的主体,即JWT所面向的用户。
//Audience(受众):用于标识JWT的接收者。
//ExpiresAt(过期时间):用于标识JWT的过期时间,以Unix时间戳表示。
//NotBefore(生效时间):用于标识JWT的生效时间,以Unix时间戳表示。
//IssuedAt(签发时间):用于标识JWT的签发时间,以Unix时间戳表示。
//JWT ID(编号):用于标识JWT的唯一ID。
第二步创建签名
var mySecret = []byte("秘密")
func KeyFunc(_ *jwt.Token) (i interface{}, err error) {
return mySecret, nil
}
第三步创建GenToken函数 来创建accessToken 和refreshToken
access token: 用于验证用户在系统中的身份和权限,并且在用户进行请求时,服务器会使用access token来验证用户的身份和权限,从而决定是否允许用户的请求。
refresh token: 用于获取新的access token,因为access token通常有一定的有效期,一旦过期,用户就需要使用refresh token来获取新的access token,从而继续访问系统资源
func GenToken(username string, userID uint64) (aToken, rToken string, err error) {
//创建一个自己的声明
c := MyClaims{
userID,
username,
jwt.StandardClaims{
ExpiresAt: int64(TakenExpireDuration), //过期时间
Issuer: "xb", //签发人
},
}
//加密并获得完整的编码后的字符串token
aToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString(mySecret)
//刷新token不需要自定义数据,
rToken, err = jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Second * 30).Unix(),
Issuer: "xb",
}).SignedString(mySecret)
return
}
第四步解析JWT
func ParseToken(tokenString string) (claims *MyClaims, err error) {
//解析token
var token *jwt.Token
claims = new(MyClaims)
token, err = jwt.ParseWithClaims(tokenString, claims, KeyFunc)
//首先解析tokenString字符串,然后用mySecret签名验证,如果验证成功后将数据存入结构体 claims中
if err != nil {
return
}
if !token.Valid {
err = errors.New("invalid token")
}
return
}
第五步刷新accesstoken
// 刷新accessToken
func RefreshToken(aToken, rToken string) (newAToken, newRToken string, err error) {
//refresh token 无效直接返回
if _, err = jwt.Parse(rToken, KeyFunc); err != nil {
return
}
//从旧的access token中解析出claims数据, 解析出payload负载信息
var claims *MyClaims
_, err = jwt.ParseWithClaims(aToken, claims, KeyFunc)
v, _ := err.(*jwt.ValidationError)
//当access token 是过期错误 并且refresh token 没有过期就创建一个新的access token
if v.Errors == jwt.ValidationErrorExpired {
return GenToken(claims.Username, claims.UserID)
}
return
}