猿问

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

设置: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 string

unencodedToken := *input.IDToken

fmt.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 的域


慕哥6287543
浏览 296回答 1
1回答

慕丝7291255

接近:https ://stackoverflow.com/a/61718113/12563520我们的朋友在这里写了如何正确验证 JWT。token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {&nbsp; &nbsp; token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {&nbsp; &nbsp; if _, ok := token.Method.(*jwt.SigningMethodRS256); !ok {&nbsp; &nbsp; &nbsp; &nbsp; return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])&nbsp; &nbsp; }&nbsp; &nbsp; kid, ok := token.Header["kid"].(string)&nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; return nil, errors.New("kid header not found")&nbsp; &nbsp; }&nbsp; &nbsp; keys := keySet.LookupKeyID(kid);&nbsp; &nbsp; if len(keys) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return nil, fmt.Errorf("key %v not found", kid)&nbsp; &nbsp; }&nbsp; &nbsp; // keys[0].Materialize() doesn't exist anymore&nbsp; &nbsp; var raw interface{}&nbsp; &nbsp; return raw, keys[0].Raw(&raw)})这是我的完整实现,以满足谷歌从这里提供的说明:https ://developers.google.com/identity/sign-in/web/backend-auth我可能比我需要的更频繁地验证事情,所以如果有人想编辑或评论,我会做出改变。// Get the Key&nbsp; &nbsp; unencodedToken := *input.IDToken&nbsp; &nbsp; fetchedToken, err := jwk.FetchHTTP("https://www.googleapis.com/oauth2/v3/certs")&nbsp; &nbsp; // Parse the token with standard claims&nbsp; &nbsp; token, err := jwt.ParseWithClaims(unencodedToken, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {&nbsp; &nbsp; &nbsp; &nbsp; if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Unexpected token signing method", token)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; kid, ok := token.Header["kid"].(string)&nbsp; &nbsp; &nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Could not find Key ID")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Could not find key ID in token:", token)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; keys := fetchedToken.LookupKeyID(kid)&nbsp; &nbsp; &nbsp; &nbsp; if len(keys) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Could not find key in the signature")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Could not find key in the signature: ", token)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var empty interface{}&nbsp; &nbsp; &nbsp; &nbsp; return empty, keys[0].Raw(&empty)&nbsp; &nbsp; })&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Could not decode the token")&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(err)&nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Could not decode the token: ", token)&nbsp; &nbsp; }&nbsp; &nbsp; // Check if the token is valid&nbsp; &nbsp; if token.Valid {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Valid token")&nbsp; &nbsp; } else if ve, ok := err.(*jwt.ValidationError); ok {&nbsp; &nbsp; &nbsp; &nbsp; if ve.Errors&jwt.ValidationErrorMalformed != 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("That's not even a token")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Invalid Token")&nbsp; &nbsp; &nbsp; &nbsp; } else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Token is either expired or not active yet&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Expired token")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Expired Token:", token)&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Couldn't handle this token", token, err)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf(err.Error())&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Couldn't handle this token", token, err)&nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf(err.Error())&nbsp; &nbsp; }&nbsp; &nbsp; // Check if the claims are valid&nbsp; &nbsp; err = token.Claims.Valid()&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Failed validity check", err)&nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Failed validity check on token", token, err.Error())&nbsp; &nbsp; }&nbsp; &nbsp; // Check the custom claims&nbsp; &nbsp; if claims, ok := token.Claims.(*jwt.StandardClaims); ok && token.Valid {&nbsp; &nbsp; &nbsp; &nbsp; audienceVerified := claims.VerifyAudience("773117128619-kfrd500nf8bfaq7anl7ee1ae7ucg5kp5.apps.googleusercontent.com", true)&nbsp; &nbsp; &nbsp; &nbsp; if !audienceVerified {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TODO Handle failure&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Audience unverified")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Audience unverified on token", token)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; if claims, ok := token.Claims.(*jwt.StandardClaims); ok && token.Valid {&nbsp; &nbsp; &nbsp; &nbsp; netloc := claims.VerifyIssuer("accounts.google.com", true)&nbsp; &nbsp; &nbsp; &nbsp; httpVersion := claims.VerifyIssuer("accounts.google.com", true)&nbsp; &nbsp; &nbsp; &nbsp; if !netloc && !httpVersion {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // TODO Handle failure&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Can't verify issuer")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil, gqlerror.Errorf("Can't verify issuer on token", token)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }
随时随地看视频慕课网APP

相关分类

Go
我要回答