go - 在 golang 中解析/验证来自 AzureAD 的 JWT token

标签 go azure-active-directory

我使用 OAuth2 设置了 Azure AD,并让它为我的 Web 应用程序颁发 JWT。在后续请求中,我想验证已发出的 JWT。我正在使用 github.com/dgrijalva/jwt-go 来执行此操作,但总是失败。

token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
        return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
    }
    return []byte("bW8ZcMjBCnJZS-ibX5UQDNStvx4"), nil
})
if err != nil {
    return nil, err
}

我从 MS 此处列出的公钥中随机选择 kid 声明 https://login.microsoftonline.com/common/discovery/v2.0/keys所以我迷路了,因为这不起作用。

有人以前做过这个或有任何指示吗?

最佳答案

位于 https://login.microsoftonline.com/common/discovery/v2.0/keys 的 Assets 就是所谓的 JWKS(JSON Web key 集)。如果您只想验证此服务签名的 token ,则可以使用类似于以下代码片段的内容。我专门为此用例编写了一个包:github.com/MicahParks/keyfunc

在幕后,该包将读取并解析 JWKS 中找到的加密 key ,然后根据 key ID kid 将 JWT 与这些 key 关联起来。它还具有一些关于自动刷新远程 JWKS 资源的逻辑。

package main

import (
    "context"
    "log"
    "time"

    "github.com/golang-jwt/jwt/v4"

    "github.com/MicahParks/keyfunc"
)

func main() {

    // Get the JWKS URL.
    jwksURL := "https://login.microsoftonline.com/common/discovery/v2.0/keys"

    // Create a context that, when cancelled, ends the JWKS background refresh goroutine.
    ctx, cancel := context.WithCancel(context.Background())

    // Create the keyfunc options. Use an error handler that logs. Refresh the JWKS when a JWT signed by an unknown KID
    // is found or at the specified interval. Rate limit these refreshes. Timeout the initial JWKS refresh request after
    // 10 seconds. This timeout is also used to create the initial context.Context for keyfunc.Get.
    options := keyfunc.Options{
        Ctx: ctx,
        RefreshErrorHandler: func(err error) {
            log.Printf("There was an error with the jwt.Keyfunc\nError: %s", err.Error())
        },
        RefreshInterval:   time.Hour,
        RefreshRateLimit:  time.Minute * 5,
        RefreshTimeout:    time.Second * 10,
        RefreshUnknownKID: true,
    }

    // Create the JWKS from the resource at the given URL.
    jwks, err := keyfunc.Get(jwksURL, options)
    if err != nil {
        log.Fatalf("Failed to create JWKS from resource at the given URL.\nError: %s", err.Error())
    }

    // Get a JWT to parse.
    //
    // This wasn't signed by Azure AD.
    jwtB64 := "eyJraWQiOiJlZThkNjI2ZCIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJXZWlkb25nIiwiYXVkIjoiVGFzaHVhbiIsImlzcyI6Imp3a3Mtc2VydmljZS5hcHBzcG90LmNvbSIsImlhdCI6MTYzMTM2OTk1NSwianRpIjoiNDY2M2E5MTAtZWU2MC00NzcwLTgxNjktY2I3NDdiMDljZjU0In0.LwD65d5h6U_2Xco81EClMa_1WIW4xXZl8o4b7WzY_7OgPD2tNlByxvGDzP7bKYA9Gj--1mi4Q4li4CAnKJkaHRYB17baC0H5P9lKMPuA6AnChTzLafY6yf-YadA7DmakCtIl7FNcFQQL2DXmh6gS9J6TluFoCIXj83MqETbDWpL28o3XAD_05UP8VLQzH2XzyqWKi97mOuvz-GsDp9mhBYQUgN3csNXt2v2l-bUPWe19SftNej0cxddyGu06tXUtaS6K0oe0TTbaqc3hmfEiu5G0J8U6ztTUMwXkBvaknE640NPgMQJqBaey0E4u0txYgyvMvvxfwtcOrDRYqYPBnA"

    // Parse the JWT.
    var token *jwt.Token
    if token, err = jwt.Parse(jwtB64, jwks.Keyfunc); err != nil {
        log.Fatalf("Failed to parse the JWT.\nError: %s", err.Error())
    }

    // Check if the token is valid.
    if !token.Valid {
        log.Fatalf("The token is not valid.")
    }
    log.Println("The token is valid.")

    // End the background refresh goroutine when it's no longer needed.
    cancel()

    // This will be ineffectual because the line above this canceled the parent context.Context.
    // This method call is idempotent similar to context.CancelFunc.
    jwks.EndBackground()
}

关于go - 在 golang 中解析/验证来自 AzureAD 的 JWT token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70900067/

相关文章:

Golang 中的字符串内存使用

go - 使用 golang 在 google admin sdk api 上获取 400 invalid_grant。有什么建议么?

sql - 如何在go中使用sql server包

azure - 使用B2B邀请时App是否需要 Multi-Tenancy

templates - 在 Go 中显示 html 模板的计数

html - 如何在 golang gin web 框架中使用 golang 数据呈现 HTML?

c# - Azure AD 授权错误 AuthenticationFailed : IDX10501: Signature validation failed. 无法匹配 'kid'

azure - 有没有办法在 Azure AD for applications 中设置自动响应

azure - 在常规 Azure AD 租户内创建 Azure AD B2C 应用程序注册的目的是什么?

azure - Azure AD 和 Power 中的访问 token 范围问题