将 google idToken 交换为本地 openId 令牌 c#

Exchanging a google idToken for local openId token c#

我正在使用这个 github 项目 https://github.com/openiddict/openiddict-core,它很棒。但是当用户使用外部身份提供者时,我不知道程序应该是什么,或者如何实现它们,对于这个例子,我将使用 google.

我有一个带有 aspnet 核心 webAPI 的 angular2 应用程序 运行。我所有的本地登录都运行良好,我使用用户名和密码调用 connect/token,并返回了 accessToken。

现在我需要将 google 实施为外部身份提供者。我已按照 here 的所有步骤实现 google 登录按钮。这会在用户登录时打开一个弹出窗口。这是我为 google 按钮创建的代码。

// Angular hook that allows for interaction with elements inserted by the
// rendering of a view.
ngAfterViewInit() {
    // check if the google client id is in the pages meta tags
    if (document.querySelector("meta[name='google-signin-client_id']")) {
        // Converts the Google login button stub to an actual button.
        gapi.signin2.render(
            'google-login-button',
            {
                "onSuccess": this.onGoogleLoginSuccess,
                "scope": "profile",
                "theme": "dark"
            });
    }
}

onGoogleLoginSuccess(loggedInUser) {
    let idToken = loggedInUser.getAuthResponse().id_token;

    // here i can pass the idToken up to my server and validate it
}

现在我有一个来自 google 的 idToken。 google 页面上的下一步发现 here 说我需要验证 google accessToken,我可以这样做,但是如何交换我从 [=25 获得的 accessToken =],并创建可在我的应用程序上使用的本地 accessToken?

编辑:此答案已更新为使用 OpenIddict 3.x。


The next step on the google pages found here says that i need to validate the google accessToken, which i can do, but how do i exchange the accessToken that i have from google, and create local accessToken which can be used on my application?

您尝试实施的流程称为断言授权。您可以阅读 了解它。

OpenIddict 完全支持自定义授权,因此您可以在令牌端点操作中轻松实现:

[HttpPost("~/connect/token"), Produces("application/json")]
public IActionResult Exchange()
{
    var request = HttpContext.GetOpenIddictServerRequest();
    if (request.GrantType == "urn:ietf:params:oauth:grant-type:google_identity_token")
    {
        // Reject the request if the "assertion" parameter is missing.
        if (string.IsNullOrEmpty(request.Assertion))
        {
            return Forbid(
                authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,
                properties: new AuthenticationProperties(new Dictionary<string, string>
                {
                    [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidRequest,
                    [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                        "The mandatory 'assertion' parameter was missing."
                }));
        }

        // Create a new ClaimsIdentity containing the claims that
        // will be used to create an id_token and/or an access token.
        var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType);

        // Manually validate the identity token issued by Google, including the
        // issuer, the signature and the audience. Then, copy the claims you need
        // to the "identity" instance and call SetDestinations on each claim to
        // allow them to be persisted to either access or identity tokens (or both).
        //
        // Note: the identity MUST contain a "sub" claim containing the user ID.

        var principal = new ClaimsPrincipal(identity);

        foreach (var claim in principal.Claims)
        {
            claim.SetDestinations(claim.Type switch
            {
                "name" => new[]
                {
                    Destinations.AccessToken,
                    Destinations.IdentityToken
                },

                _ => new[] { Destinations.AccessToken },
            });
        }

        return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
    }

    throw new InvalidOperationException("The specified grant type is not supported.");
}

请注意,您还必须在 OpenIddict 服务器选项中启用它:

services.AddOpenIddict()
    // ...

    .AddServer(options =>
    {
        // ...

        options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:google_identity_token");
    });

发送令牌请求时,确保使用正确的 grant_type 并将您的 id_token 作为 assertion 参数发送,它应该可以工作。这是 Postman 的示例(用于 Facebook 访问令牌,但它的工作方式完全相同):

也就是说,您在实施令牌验证例程时必须格外小心,因为这一步特别容易出错。验证所有内容非常重要,包括观众(否则,your server would be vulnerable to confused deputy attacks)。