为了账号安全,请及时绑定邮箱和手机立即绑定

“使用 Google 登录”JWT 发送到我的服务器时无效

“使用 Google 登录”JWT 发送到我的服务器时无效

Go
慕哥6287543 2022-06-21 16:20:23
设置:React 前端和 Golang 后端。我的 React 前端成功从 Google 获取令牌:<GoogleLogin   clientId="<client-id>.apps.googleusercontent.com"   onSuccess={response => responseGoogle(response)}></GoogleLogin>我有一个突变可以发送我需要的信息:initiateTestMutation({ variables: {    idToken: response.getAuthResponse().id_token,    email: response.profileObj.email,    givenName: response.profileObj.givenName,    familyName: response.profileObj.familyName, }}然后它发送一个我可以用 jwt.io 解码的令牌,但它显示“无效签名”。它包含我的正确信息,但同样无效。在我的服务器端,我也尝试验证它并失败了。// This is the token as a stringunencodedToken := *input.IDTokenfmt.Println(unencodedToken)token, err := jwt.Parse(unencodedToken, func(token *jwt.Token) (interface{}, error){    return []byte("What goes here?"), nil})if err != nil {    fmt.Println("Could not decode the token")    fmt.Println(err)}if token.Valid {    fmt.Println("Valid token")} else if ve, ok := err.(*jwt.ValidationError); ok {    if ve.Errors&jwt.ValidationErrorMalformed != 0 {        fmt.Println("That's not even a token")    } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {        // Token is either expired or not active yet        fmt.Println("Expired token")    } else {        fmt.Println("Couldn't handle this token:", err)    }} else {    fmt.Println("Couldn't handle this token:", err)}其他信息:这一切都在本地完成。app.localhost是请求作为已批准来源添加的 JWT 的域
查看完整描述

1 回答

?
慕丝7291255

TA贡献1859条经验 获得超6个赞

接近:https ://stackoverflow.com/a/61718113/12563520


我们的朋友在这里写了如何正确验证 JWT。



token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {

    if _, ok := token.Method.(*jwt.SigningMethodRS256); !ok {

        return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])

    }

    kid, ok := token.Header["kid"].(string)

    if !ok {

        return nil, errors.New("kid header not found")

    }

    keys := keySet.LookupKeyID(kid);

    if len(keys) == 0 {

         return nil, fmt.Errorf("key %v not found", kid)

    }

    // keys[0].Materialize() doesn't exist anymore

    var raw interface{}

    return raw, keys[0].Raw(&raw)

})

这是我的完整实现,以满足谷歌从这里提供的说明:https ://developers.google.com/identity/sign-in/web/backend-auth


我可能比我需要的更频繁地验证事情,所以如果有人想编辑或评论,我会做出改变。


// Get the Key

    unencodedToken := *input.IDToken

    fetchedToken, err := jwk.FetchHTTP("https://www.googleapis.com/oauth2/v3/certs")


    // Parse the token with standard claims

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

        if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {

            return nil, gqlerror.Errorf("Unexpected token signing method", token)

        }

        kid, ok := token.Header["kid"].(string)

        if !ok {

            fmt.Println("Could not find Key ID")

            return nil, gqlerror.Errorf("Could not find key ID in token:", token)

        }

        keys := fetchedToken.LookupKeyID(kid)

        if len(keys) == 0 {

            fmt.Println("Could not find key in the signature")

            return nil, gqlerror.Errorf("Could not find key in the signature: ", token)

        }

        var empty interface{}

        return empty, keys[0].Raw(&empty)

    })

    if err != nil {

        fmt.Println("Could not decode the token")

        fmt.Println(err)

        return nil, gqlerror.Errorf("Could not decode the token: ", token)

    }

    // Check if the token is valid

    if token.Valid {

        fmt.Println("Valid token")

    } else if ve, ok := err.(*jwt.ValidationError); ok {

        if ve.Errors&jwt.ValidationErrorMalformed != 0 {

            fmt.Println("That's not even a token")

            return nil, gqlerror.Errorf("Invalid Token")

        } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {

            // Token is either expired or not active yet

            fmt.Println("Expired token")

            return nil, gqlerror.Errorf("Expired Token:", token)

        } else {

            fmt.Println("Couldn't handle this token", token, err)

            return nil, gqlerror.Errorf(err.Error())

        }

    } else {

        fmt.Println("Couldn't handle this token", token, err)

        return nil, gqlerror.Errorf(err.Error())

    }

    // Check if the claims are valid

    err = token.Claims.Valid()

    if err != nil {

        fmt.Println("Failed validity check", err)

        return nil, gqlerror.Errorf("Failed validity check on token", token, err.Error())

    }

    // Check the custom claims

    if claims, ok := token.Claims.(*jwt.StandardClaims); ok && token.Valid {

        audienceVerified := claims.VerifyAudience("773117128619-kfrd500nf8bfaq7anl7ee1ae7ucg5kp5.apps.googleusercontent.com", true)

        if !audienceVerified {

            // TODO Handle failure

            fmt.Println("Audience unverified")

            return nil, gqlerror.Errorf("Audience unverified on token", token)

        }

    }


    if claims, ok := token.Claims.(*jwt.StandardClaims); ok && token.Valid {

        netloc := claims.VerifyIssuer("accounts.google.com", true)

        httpVersion := claims.VerifyIssuer("accounts.google.com", true)

        if !netloc && !httpVersion {

            // TODO Handle failure

            fmt.Println("Can't verify issuer")

            return nil, gqlerror.Errorf("Can't verify issuer on token", token)

        }

    }


查看完整回答
反对 回复 2022-06-21
  • 1 回答
  • 0 关注
  • 295 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号