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

Gil*_*rdo 5 c# openid oauth asp.net-core openiddict

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

我有一个angular2 app运行,带有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
}
Run Code Online (Sandbox Code Playgroud)

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

Kév*_*let 9

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

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

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

[HttpPost("~/connect/token")]
[Produces("application/json")]
public IActionResult Exchange(OpenIdConnectRequest request)
{
    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."
    });
}
Run Code Online (Sandbox Code Playgroud)

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

// Register the OpenIddict services, including the default Entity Framework stores.
services.AddOpenIddict()
    // Register the Entity Framework stores.
    .AddEntityFrameworkCoreStores<ApplicationDbContext>()

    // Register the ASP.NET Core MVC binder used by OpenIddict.
    // Note: if you don't call this method, you won't be able to
    // bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
    .AddMvcBinders()

    // Enable the token endpoint.
    .EnableTokenEndpoint("/connect/token")

    // Enable the password flow, the refresh
    // token flow and a custom grant type.
    .AllowPasswordFlow()
    .AllowRefreshTokenFlow()
    .AllowCustomFlow("urn:ietf:params:oauth:grant-type:google_identity_token")

    // During development, you can disable the HTTPS requirement.
    .DisableHttpsRequirement();
Run Code Online (Sandbox Code Playgroud)

发送令牌请求时,请确保使用右侧grant_type并将您的id_token作为assertion参数发送,它应该可以正常工作.这是Postman的一个例子(对于Facebook访问令牌,但它的工作原理完全相同):

在此输入图像描述

也就是说,在实现令牌验证例程时必须非常小心,因为此步骤特别容易出错.验证所有内容非常重要,包括受众(否则,您的服务器将容易受到混乱的副攻击).

  • 你的答案每次都让我惊讶!非常感谢 (3认同)
  • @Makla这个答案仍然有效,而OpenIddict仍然支持这种情况."OAuth2令牌交换"草案尚未标准化,[但上个月发布了新版本](https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-07),所以它绝对是在正确的轨道上.也就是说,谷歌或Facebook等主要提供商可能需要很多年才开始实施它(FWIW,Facebook仍在使用较旧的OAuth2草案,不符合最终的RFC). (2认同)
  • 现在这是一个拟议的标准,只是为了跟进:https://tools.ietf.org/html/rfc8693,我想它不会改变答案的有效性,不是吗? (2认同)