我正在使用以下代码创建令牌
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
Subject: string(user.Id),
})
tokenString, err := token.SignedString([]byte("secret"))
并尝试使用以下代码解析它们
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, UnauthorizedError
}
return []byte("secret"), nil
})
if err != nil {
return -1, UnauthorizedError
}
if !token.Valid {
return -1, UnauthorizedError
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return -1, UnauthorizedError
}
logrus.Info(claims)
为什么我不能将我的声明投向StandardClaims并访问Claims.Subject?
答案 0 :(得分:3)
为什么我不能对
StandardClaims
声明所有权并访问claims.Subject
?
从概念上讲,这是不可能的,因为jwt.Parse
函数by default将声明解析为jwt.MapClaims
的实例。这是与jwt.StandardClaims
根本不同的数据结构;编译器无法使用简单的类型转换在两者之间自动转换,因为它们表示数据的方式不同。
该库提供了ParseWithClaims
函数,该函数允许您为要声明为的声明指定jwt.Claims
接口的自己的实现者。您可以传递jwt.StandardClaims
的实例。例如:
token, err := jwt.ParseWithClaims(
tokenString, &jwt.StandardClaims{},
func(token *jwt.Token) (interface{}, error) {
// ...
},
)
如果可能,将对声明进行解析并将其解码为变量token.Claims
。存储在此变量中的值的基础类型(动态 1 )类型为*jwt.StandardClaims
。可以在类型断言中使用它来从接口类型中恢复标准声明:
claims, ok := token.Claims.(*jwt.StandardClaims)
if !ok {
// handle type assertion failure
}
// do something with "claims"
让我们进一步研究语言规范和库定义,以便对该要求进行更严格的评估。
jwt.MapClaims
是具有基础类型map[string]interface{}
(code)的已定义类型。
jwt.StandardClaims
是已定义的struct
类型(code):
type StandardClaims struct {
// Field set elided for brevity, as it is unimportant to the
// answer.
}
这两种类型都实现了jwt.Claims
接口类型(definition),因此可以分配给类型为jwt.Claims
的变量:
type Claims interface {
Valid() bool
}
Token
结构的Claims
类型为jwt.Claims
的{{3}} –任何实现Claims
接口的值都可以分配给{{1} }。
当Claims
不是接口类型(动态类型 <)时,形式为x.(T)
的类型声明表达式的语言规范field是有效的T
的sup> 1 必须与类型x
相同。在这里,您希望评估断言T
;即声明的类型不是接口类型。
x.(*jwt.StandardClaims)
的{{3}}最终在默认解析器上调用jwt.Parse
,传入jwt.ParseWithClaims
的实例作为声明目的地:
jwt.MapClaims
因此,结果令牌中func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}
字段的动态类型为Claims
。此类型与类型jwt.MapClaims
(即不完全相同),因为用户定义的类型与除其自身之外的其他任何类型的specifies不同。因此,类型断言失败。
1 动态类型(code):在Go中回想起,接口类型可以由实现以下类型的超集的任何类型隐式实现:接口中指定的方法。如果我们定义类型为jwt.StandardClaims
的接口,则变量声明MyInterface
具有静态类型(在编译时定义)var x MyInterface
。但是,在运行时,我们可以将实现MyInterface
的任何值分配给MyInterface
。随时分配给x
的值的基础类型(实现接口的类型)指定变量的动态类型。