jwt是一个标准的东西,是一个经过加密的字符串。主要用来做web鉴权使用,当然也可以用在所有需要对信息加密的场景。
jwt结构
jwt三部分组成:标头、有效载荷、签名。
1 标头主要有两个数据,说明加密算法和令牌类型
{ "alg": "HS256", "typ": "JWT" }
2 有效载荷分三种类型:注册声明、公共声明、私人声明。
注册声明主要有7个如下
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
注册声明并不强制要求有,但是有几个很重要,exp到期时间参数在golang-jwt中会根据该参数自动过期。
1 jwt的生成
golang-jwt是go语言最常用的一个jwt包。
import(
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v4/request"
)
//第一种方式
func GetToken(secretKey string, iat, seconds, uid int64) (string, error) {
claims := make(jwt.MapClaims) //数据仓声明
claims["exp"] = iat + seconds
claims["iat"] = iat
claims["uid"] = uid
token := jwt.New(jwt.SigningMethodHS256) //token对象
token.Claims = claims //token添加数据仓
return token.SignedString([]byte(secretKey))
}
//第二种方式
func GetToken2(secretKey string, iat, seconds, uid int64) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"exp": iat+seconds, "uid": 123.1, "iat": iat,"uid":uid})
tokenstr, error := token.SignedString(secretKey)
return tokenstr, error
}
jwt.MapClaims 本质就是一个 map[string]interface{},jwt中加载的所有数据都通过MapClaims进行设置。
这里边最终要的就是exp 有了这个参数解析时候才能验证token串是否有效
2 jwt加密串的解析
//第一种
tk, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return []byte(secretKey), nil
})
if tk.Valid{
for k,v:=range tk.Claims.(jwt.MapClaims){
fmt.Println(k,":",v)
}
}
jwt.Parse解析后返回一个token对象,token对象里有个Valid属性,标识该token串是否有效,除了验证token串的加密有效性还会验证exp是否过期。token对象的Claims属性是个接口,可以转城jwt.MapClaims,从而拿到token中的附载数据。
//第二种
r := map[string]interface{}{
"exp": time.Now().Unix(),
}
tk, err := jwt.ParseWithClaims(token, jwt.MapClaims(r), func(t *jwt.Token) (interface{}, error) {
return []byte(sec), nil
})
jwt.ParseWithClaims多了一个默认jwt.MapClaims参数,该参数值中的数据都是默认值,当token串中无对应数据则会用默认值,建议添加默认exp参数值。
3 request中jwt解析
jwt经常会用在web中,在golang-jwt库中,也有个专门的request包来进行处理。
import(
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v4/request"
)
sec:="abc"
now:=time.Now().Unix()
token,_:=GetToken(abc,now+30,now,1)
r := httptest.NewRequest(http.MethodGet, "http://www.abc.com", nil)
r.Header.Add("Authorization", token)
tk, err := request.ParseFromRequest(r, request.AuthorizationHeaderExtractor, func(t *jwt.Token) (interface{}, error) {
return []byte(sec), nil
})
request.ParseFromRequest中的第二个参数是一个提取器,类型为request.Extractor,这是一个接口,原型如下:
type Extractor interface {
ExtractToken(*http.Request) (string, error)
}
request.AuthorizationHeaderExtractor 实现了该接口,使用"Authorization" 对token进行提取。