7

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

我有一个 angular2 应用程序正在运行,带有一个 aspnet 核心 webAPI。我所有的本地登录都可以正常工作,我connect/token使用用户名和密码调用,并返回 accessToken。

现在我需要将 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
}

现在我有一个来自谷歌的 idToken。在此处找到的谷歌页面上的下一步说我需要验证谷歌 accessToken,我可以这样做,但是如何交换我从谷歌获得的 accessToken,并创建可以在我的应用程序上使用的本地 accessToken?

4

1 回答 1

14

在此处找到的谷歌页面上的下一步说我需要验证谷歌 accessToken,我可以这样做,但是我如何交换我从谷歌获得的 accessToken,并创建可以在我的应用程序上使用的本地 accessToken?

您尝试实现的流程称为断言授权。您可以阅读此其他 SO 帖子以获取有关它的更多信息。

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

[HttpPost("~/connect/token")]
[Produces("application/json")]
public IActionResult Exchange()
{
    var request = HttpContext.GetOpenIdConnectRequest();
    if (request.IsPasswordGrantType())
    {
        // ...
    }

    else 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 BadRequest(new OpenIdConnectResponse
            {
                Error = OpenIdConnectConstants.Errors.InvalidRequest,
                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(OpenIdConnectServerDefaults.AuthenticationScheme);

        // 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.

        // Create a new authentication ticket holding the user identity.
        var ticket = new AuthenticationTicket(
            new ClaimsPrincipal(identity),
            new AuthenticationProperties(),
            OpenIdConnectServerDefaults.AuthenticationScheme);

        ticket.SetScopes(
            OpenIdConnectConstants.Scopes.OpenId,
            OpenIdConnectConstants.Scopes.OfflineAccess);

        return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
    }

    return BadRequest(new OpenIdConnectResponse
    {
        Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
        ErrorDescription = "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 访问令牌,但它的工作方式完全相同):

在此处输入图像描述

也就是说,在实施令牌验证例程时必须非常小心,因为这一步特别容易出错。验证所有内容非常重要,包括观众(否则,您的服务器将容易受到混淆代理攻击)。

于 2016-10-26T11:20:04.823 回答