这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记。
前言:在开发项目的时候,我们总会苦恼怎么鉴定用户并且判断能够使用哪些服务。在漫长的鉴权演化进程中,开发者们从Session到Cookie,最后演变成了Token。这篇文章不会对比这三个鉴权方式的优劣,而是通过golang-jwt模块向大家介绍jwt的用处。
什么是JWT?
JWT(Json Web Token)是一种开放的行业标准(RFC 7519)方法,用于在两方之间安全地表示声明。我们可以将JWT分成三个部分:令牌头(alg算法类型与type生成类型)、传递的信息与验证签名。
上图通过颜色标明各个字段存储的信息,而这段信息将会储存在客户端内,需要时可将令牌通过请求头上传至服务端,服务端解析后继续执行操作。
Golang-jwt模块将鉴权的操作最简化,以便于开发者更方便调用。譬如我们需要在JWT中存入生成时间和用户ID,生成和匹配代码如下:
import (
"fmt"
"time"
"github.com/golang-jwt/jwt"
)
var Secret = []byte("TestSecret")
// 签发token, 仅传入userID, token令牌中仅包含id和创建时间
func Sign(userID uint) (string, error) {
// 使用HS256生成token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
// 存入信息
"id": userID,
"nbf": time.Now().Unix(),
})
// 加密
tokenString, err := token.SignedString([]byte(Secret))
return tokenString, err
}
// 解析token, 仅传入token字符串, 仅判断是否转换成功与令牌是否超时
func Parse(tokenString string) (uint, error) {
// 通过JWT令牌头获取加密算法
token, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("加密方式错误: %v", t.Header["alg"])
}
return []byte(Secret), nil
})
if err != nil {
fmt.Println("token获取错误")
}
// 解析token存储的消息
claims, ok := token.Claims.(jwt.MapClaims)
if !(ok && token.Valid) {
fmt.Println("token解析错误, 请重新登陆获取")
} else {
fmt.Println(claims["id"], claims["nbf"])
}
}
在解析出用户的ID后,我们可以通过ID从数据库中查找相应的用户信息。而且只要密钥不被泄露,这个令牌的安全系数也非常高。更重要的是,这个令牌只会存在于客户端中,不会消耗服务端的存储。
希望这篇文章能够快速上手JWT的应用!