简体   繁体   English

dgrijalva/jwt-go 可以将声明转换为 MapClaims 而不是 StandardClaims?

[英]dgrijalva/jwt-go can cast claims to MapClaims but not StandardClaims?

I am creating the token with the following code我正在使用以下代码创建令牌

token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
    Subject: string(user.Id),
})

tokenString, err := token.SignedString([]byte("secret"))

and trying to parse them with the following code并尝试使用以下代码解析它们

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)

Why can I not cast my claims to StandardClaims and access claims.Subject?为什么我不能将我的声明转换为 StandardClaims 并访问 claim.Subject?

Why can I not cast my claims to StandardClaims and access claims.Subject ?为什么我不能将我的声明转换为StandardClaims并访问claims.Subject

Conceptually, this is not possible because the jwt.Parse function by default parses claims into an instance of jwt.MapClaims .从概念上讲,这是不可能的,因为jwt.Parse函数默认将声明解析为jwt.MapClaims的实例。 This is a fundamentally different data structure to jwt.StandardClaims ;这是与jwt.StandardClaims完全不同的数据结构; there is no way the compiler can automatically convert between the two using a simple type conversion as they represent the data differently.编译器无法使用简单的类型转换在两者之间自动转换,因为它们表示数据的方式不同。

Resolution解析度

The library provides the ParseWithClaims function, which allows you to specify your own implementer of the jwt.Claims interface for claims to be decoded into.该库提供了ParseWithClaims函数,它允许您指定自己的jwt.Claims接口实现者,以便将声明解码为。 You can pass an instance of jwt.StandardClaims .您可以传递jwt.StandardClaims的实例。 For example:例如:

token, err := jwt.ParseWithClaims(
    tokenString, &jwt.StandardClaims{},
    func(token *jwt.Token) (interface{}, error) {
        // ...
    },
)

If possible, the claims will be parsed and decoded into the variable token.Claims .如果可能,声明将被解析并解码为变量token.Claims The underlying (dynamic 1 ) type of the value stored into this variable will be *jwt.StandardClaims .存储到此变量中的值的基础(动态1 )类型将是*jwt.StandardClaims This can be used in a type assertion to recover the standard claims from the interface type:这可用于类型断言以从接口类型恢复标准声明:

claims, ok := token.Claims.(*jwt.StandardClaims)
if !ok {
    // handle type assertion failure
}
// do something with "claims"

Let's dig into the language specification and library definition some more to provide a more rigorous assessment of this claim.让我们更深入地研究语言规范和库定义,以对该声明进行更严格的评估。

Background understanding of package types包类型的背景理解

jwt.MapClaims is a defined type with underlying type map[string]interface{} ( code ). jwt.MapClaims是一个定义的类型,具有底层类型map[string]interface{} ( code )。

jwt.StandardClaims is a defined struct type ( code ): jwt.StandardClaims是一个定义的struct类型( 代码):

type StandardClaims struct {
    // Field set elided for brevity, as it is unimportant to the
    // answer.
}

Both types implement the jwt.Claims interface type ( definition ), so is assignable to a variable of type jwt.Claims :这两种类型都实现了jwt.Claims接口类型( 定义),因此可以分配给jwt.Claims类型的变量:

type Claims interface {
    Valid() bool
}

The Token struct has a field called Claims of type jwt.Claims – any value which implements the Claims interface can be assigned to Claims . Token结构有一个名为Claims字段,类型为jwt.Claims任何实现Claims接口的值都可以分配给Claims

Type assertion definition类型断言定义

The language spec specifies for a type assertion expression of the form x.(T) to be valid when T is not an interface type, the dynamic type 1 of x must be identical to the type T .语言规范指定x.(T)形式的类型断言表达式在T不是接口类型时有效, x动态类型1必须类型T相同 Here, you wish to evaluate the assertion x.(*jwt.StandardClaims) ;在这里,您希望评估断言x.(*jwt.StandardClaims) ie the asserted type is not an interface type.即断言类型不是接口类型。

The code for jwt.Parse eventually calls jwt.ParseWithClaims on the default parser, passing in an instance of jwt.MapClaims for the claims destination: jwt.Parse代码最终在默认解析器上调用jwt.ParseWithClaims ,传入一个jwt.MapClaims的实例作为声明目的地:

func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
    return p.ParseWithClaims(tokenString, MapClaims{}, keyFunc)
}

so the dynamic type of the Claims field in your resulting token is of type jwt.MapClaims .所以结果令牌中Claims字段的动态类型是jwt.MapClaims类型。 This type is different (ie not identical) to the type jwt.StandardClaims , because user-defined types are always different from any other type except themselves.此类型与类型jwt.StandardClaims不同(即不相同),因为用户定义的类型总是与除自身之外的任何其他类型不同。 Hence, the type assertion fails.因此,类型断言失败。


1 Dynamic types ( ref ): recall in Go that interface types are fulfilled implicitly by any type which implements a super-set of the methods specified in an interface. 1动态类型ref ):在 Go 中回忆一下,接口类型由实现接口中指定方法的超集的任何类型隐式实现。 If we define an interface of type MyInterface , the variable declaration var x MyInterface has static type (defined at compile time) MyInterface .如果我们定义一个MyInterface类型的接口,变量声明var x MyInterface具有静态类型(在编译时定义) MyInterface However, at runtime, we can assign any value which implements MyInterface to x .但是,在运行时,我们可以将实现MyInterface任何值分配给x The underlying type of the value assigned to x at any moment (the type which implements the interface) specifies the dynamic type of the variable.任何时候分配给x的值的基础类型(实现接口的类型)指定变量的动态类型

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM