验证谷歌的OpenID连接智威汤逊ID令牌令牌、OpenID、智威汤逊、ID

2023-09-03 17:02:54 作者:奇葩女王放光芒

我想升级我的MVC的网站使用新的OpenID的连接标准。该OWIN中间件似乎是pretty的强劲,但遗憾的是只支持 form_post响应类型。这意味着,谷歌是不兼容的,因为它返回一个链接的所有令牌后一个#,所以他们从来没有到达服务器和从未触发中间件

I'm trying to upgrade my MVC website to use the new OpenID Connect standard. The OWIN middleware seems to be pretty robust, but unfortunately only supports the "form_post" response type. This means that Google isn't compatible, as it returns all the tokens in a the url after a "#", so they never reach the server and never trigger the middleware.

我试图触发在中间件自己的应对处理程序,但这似乎并没有在所有的工作,所以我已经得到了解析出返回的索赔,并将它们发布到一个控制器动作一个简单的JavaScript文件进行处理。

I've tried to trigger the response handlers in the middleware myself, but that doesn't seem to work at all, so I've got a simply javascript file that parses out the returned claims and POSTs them to a controller action for processing.

但问题是,即使我让他们在服务器端,我不能正确地分析它们。我得到的错误是这样的:

Problem is, even when I get them on the server side I can't parse them correctly. The error I get looks like this:

IDX10500: Signature validation failed. Unable to resolve     
SecurityKeyIdentifier: 'SecurityKeyIdentifier
(
   IsReadOnly = False,
   Count = 1,
   Clause[0] = System.IdentityModel.Tokens.NamedKeySecurityKeyIdentifierClause
),
token: '{
    "alg":"RS256",
    "kid":"073a3204ec09d050f5fd26460d7ddaf4b4ec7561"
}.
{
    "iss":"accounts.google.com",
    "sub":"100330116539301590598",
    "azp":"1061880999501-b47blhmmeprkvhcsnqmhfc7t20gvlgfl.apps.googleusercontent.com",
    "nonce":"7c8c3656118e4273a397c7d58e108eb1",
    "email_verified":true,
    "aud":"1061880999501-b47blhmmeprkvhcsnqmhfc7t20gvlgfl.apps.googleusercontent.com",
    "iat":1429556543,"exp\":1429560143
    }'."
}

我的记号验证code遵循了善良的人们开发IdentityServer列出的例子

My token verification code follows the example outlined by the good people developing IdentityServer

    private async Task<IEnumerable<Claim>> ValidateIdentityTokenAsync(string idToken, string state)
    {
        // New Stuff
        var token = new JwtSecurityToken(idToken);
        var jwtHandler = new JwtSecurityTokenHandler();
        byte[][] certBytes = getGoogleCertBytes();

        for (int i = 0; i < certBytes.Length; i++)
        {
            var certificate = new X509Certificate2(certBytes[i]);
            var certToken = new X509SecurityToken(certificate);

            // Set up token validation
            var tokenValidationParameters = new TokenValidationParameters();
            tokenValidationParameters.ValidAudience = googleClientId;
            tokenValidationParameters.IssuerSigningToken = certToken;
            tokenValidationParameters.ValidIssuer = "accounts.google.com";

            try
            {
                // Validate
                SecurityToken jwt;
                var claimsPrincipal = jwtHandler.ValidateToken(idToken, tokenValidationParameters, out jwt);
                if (claimsPrincipal != null)
                {
                    // Valid
                    idTokenStatus = "Valid";
                }
            }
            catch (Exception e)
            {
                if (idTokenStatus != "Valid")
                {
                    // Invalid?

                }
            }
        }

        return token.Claims;
    }

    private byte[][] getGoogleCertBytes()
    {
        // The request will be made to the authentication server.
        WebRequest request = WebRequest.Create(
            "https://www.googleapis.com/oauth2/v1/certs"
        );

        StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream());

        string responseFromServer = reader.ReadToEnd();

        String[] split = responseFromServer.Split(':');

        // There are two certificates returned from Google
        byte[][] certBytes = new byte[2][];
        int index = 0;
        UTF8Encoding utf8 = new UTF8Encoding();
        for (int i = 0; i < split.Length; i++)
        {
            if (split[i].IndexOf(beginCert) > 0)
            {
                int startSub = split[i].IndexOf(beginCert);
                int endSub = split[i].IndexOf(endCert) + endCert.Length;
                certBytes[index] = utf8.GetBytes(split[i].Substring(startSub, endSub).Replace("\\n", "\n"));
                index++;
            }
        }
        return certBytes;
    }

我知道,签名验证是不是JWTs完全必要的,但我没有丝毫的想法如何将其关闭。任何想法?

I know that Signature validation isn't completely necessary for JWTs but I haven't the slightest idea how to turn it off. Any ideas?

推荐答案

现在的问题是,在智威汤逊,其价值是关键中的关键识别用于对孩子签署智威汤逊。既然你构建手动从JWKs URI证书的数组,你丢失了密钥标识符信息。然而,验证过程需要它。

The problem is the kid in the JWT whose value is the key identifier of the key was used to sign the JWT. Since you construct an array of certificates manually from the JWKs URI, you lose the key identifier information. The validation procedure however requires it.

您需要设置 tokenValidationParameters.IssuerSigningKeyResolver 来一个函数,将返回所设置上述 tokenValidationParameters.IssuerSigningToken 。此委托的目的是为了指示运行时忽略任何'匹配'的语义,只是尝试的关键。

You'll need to set tokenValidationParameters.IssuerSigningKeyResolver to a function that will return the same key that you set above in tokenValidationParameters.IssuerSigningToken. The purpose of this delegate is to instruct the runtime to ignore any 'matching' semantics and just try the key.

请参阅本文的详细信息:JwtSecurityTokenHandler 4.0.0重大更改?

See this article for more information: JwtSecurityTokenHandler 4.0.0 Breaking Changes?

编辑:code:

tokenValidationParameters.IssuerSigningKeyResolver = (arbitrarily, declaring, these, parameters) => { return new X509SecurityKey(certificate); };
 
精彩推荐
图片推荐