草庐IT

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

coder 2023-06-30 原文

我正在使用以下代码创建 token

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?

最佳答案

Why can I not cast my claims to StandardClaims and access claims.Subject?

从概念上讲,这是不可能的,因为 jwt.Parse 函数 by default将声明解析为 jwt.MapClaims 的实例。这是与 jwt.StandardClaims 根本不同的数据结构;编译器无法使用简单的类型转换自动在两者之间进行转换,因为它们以不同的方式表示数据。

决议

该库提供了 ParseWithClaims 函数,它允许您指定您自己的 jwt.Claims 接口(interface)的实现者,以便将声明解码到其中。您可以传递 jwt.StandardClaims 的实例。例如:

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

如果可能,声明将被解析并解码为变量token.Claims。存储到此变量中的值的基础 (dynamic1) 类型将是 *jwt.StandardClaims。这可以在类型断言中用于从接口(interface)类型中恢复标准声明:

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 接口(interface)类型 ( definition ),因此可以分配给 jwt.Claims 类型的变量:

type Claims interface {
    Valid() bool
}

Token 结构有一个 field称为 jwt.Claims 类型的 Claims – 任何实现 Claims 接口(interface)的值都可以分配给 Claims

类型断言定义

语言规范 specifies要使 x.(T) 形式的类型断言表达式在 T 不是接口(interface)类型时有效,动态类型x 中的 >1 必须与 T 类型相同。在这里,您希望评估断言 x.(*jwt.StandardClaims);即断言类型不是接口(interface)类型。

code对于 jwt.Parse 最终在默认解析器上调用 jwt.ParseWithClaims,为声明目标传入一个 jwt.MapClaims 实例:

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

所以生成的 token 中 Claims 字段的动态类型是 jwt.MapClaims 类型。此类型与 jwt.StandardClaims 类型不同(即不相同),因为用户定义的类型是 always different来自除他们自己以外的任何其他类型。因此,类型断言失败。


1动态类型 ( ref ):在 Go 中回想一下,接口(interface)类型由实现方法超集的任何类型隐式实现在接口(interface)中指定。如果我们定义一个MyInterface类型的接口(interface),变量声明var x MyInterface有静态类型(在编译时定义)MyInterface。但是,在运行时,我们可以将实现 MyInterface 的任何值分配给 x。任何时刻分配给 x 的值的基础类型(实现接口(interface)的类型)指定变量的动态类型

关于go - dgrijalva/jwt-go 可以将声明转换到 MapClaims 而不是 StandardClaims?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52460230/

有关go - dgrijalva/jwt-go 可以将声明转换到 MapClaims 而不是 StandardClaims?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  4. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  5. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  6. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  9. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  10. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

随机推荐