簡體   English   中英

如何將Social Login與現有的.Net核心Web API后端和Angular SPA前端與工作OpenIddict用戶/密碼和不記名令牌集成

[英]How to integrate Social Login with existing .Net core Web API backend and Angular SPA frontend with working OpenIddict user/password and bearer token

TL; DR

問題:如何使用基於身份,用戶/密碼,承載令牌身份驗證的現有SPA / Web API應用程序實現社交登錄(OAuth2授權流程)?


我有一個現有的應用程序:

后端:配置了Identity和OpenIddict服務的.Net Core 2 Web API,具有基於對承載令牌的用戶/密碼質詢的工作認證過程。

用戶使用Identity(AspNetUsers)存儲。

Startup.cs代碼的一部分

// Register the OpenIddict services.
services.AddOpenIddict()
    .AddCore(options =>
    {
        options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();
    })
    .AddServer(options =>
    {
        options.UseMvc();
        options.EnableTokenEndpoint("/connect/token");
        options.AllowPasswordFlow();
        options.AllowRefreshTokenFlow();
        options.AcceptAnonymousClients();
        options.RegisterScopes(
            OpenIdConnectConstants.Scopes.OpenId,
            OpenIdConnectConstants.Scopes.Email,
            OpenIdConnectConstants.Scopes.Phone,
            OpenIdConnectConstants.Scopes.Profile,
            OpenIdConnectConstants.Scopes.OfflineAccess,
            OpenIddictConstants.Scopes.Roles);
    })
    .AddValidation();

前端: SPA Angular 7應用程序,它使用此后端API和令牌授權

所以基本上當前的設置是,用戶輸入SPA的用戶/密碼,調用后端/connect/token端點,驗證憑證並為客戶端生成令牌。

現在我需要集成社交登錄(OAuth2授權流程)

  1. 用戶選擇登錄提供者,
  2. 被重定向到提供者授權頁面,
  3. 被重定向回我的應用程序
  4. 需要創建Identity用戶並保存Identity UserLoginInfo數據和
  5. 提供我的應用程序令牌,以便用戶可以登錄。

我了解OAuth2授權流程,該流程需要為該提供程序請求授權代碼,然后才能獲得訪問權限的Exchange授權代碼。 我也知道這個流必須使用后端,一旦它使用像client_secret這樣無法存儲在客戶端的敏感信息。

但是在某些時候用戶需要與前端進行交互,因此考慮到這些是廣泛使用的技術,連接這些部分似乎非常困難。 我在Google上找到的所有實際例子都使用.Net Core MVC應用程序。 我還發現了這篇文章ASP.NET Core 3.0 Preview 4 - 對於SPA的身份驗證和授權似乎很有希望,但仍處於預覽版4中。

我已經創建了社交提供程序應用程序,我有client_id,client_secret。 還注冊了我的重定向網址。

我沒有成功的嘗試是:

  1. 在前端用戶選擇登錄社交提供商,
  2. 用戶被重定向到提供者授權頁面,對自己進行身份驗證
  3. 然后使用提供程序的代碼從提供程序重定向到我的前端URL( redirect_uri
  4. 我的前端調用我的后端/connect/token現有端點傳遞選定的提供者和接收到的代碼,端點被編程為接收提供者和代碼,然后
  5. 我的后端調用提供者獲取AccessToken url發布"grant_type", "authorization_code" "code", code "redirect_uri", "https://same_frontend_host/same/path" "client_id", providerClientId "client_secret", providerSecret並接收StatusCode: 401, ReasonPhrase: 'Unauthorized'回復

我究竟做錯了什么? 要讓它發揮作用真的很難。

什么有效,但這不是我需要的

使用前端進行提供者身份驗證調用和后端調用的隱式2步授權流程,以獲取我的承載令牌並創建身份用戶。 通過此設置,用戶使用社交提供程序成功登錄,遺憾的是,這不是我需要的

編輯:

制作了一個實現的圖表,它在步驟5/6失敗, StatusCode: 401, ReasonPhrase: 'Unauthorized'並且未完成其他步驟。

在此輸入圖像描述

您描述的流程幾乎與“授權跨域代碼”相對應,這是一種從未標准化的OpenID Connect流程

我不建議使用這樣的非標准選項。 相反,考慮調整流程以使您的JS客戶端專門與您自己的授權服務器通信,而不是通過使客戶端將用戶代理重定向到外部提供程序來啟動流程。

這里的關鍵思想是您自己的授權服務器應該啟動與外部提供程序的初始通信(即它應該構建授權請求並將用戶重定向到外部提供程序的授權端點)並處理最后一部分:回調授權響應。 為此,我建議使用ASP.NET Core附帶的OAuth2 / OIDC處理程序(有Google,Facebook等提供商)

當然,這並不意味着您的JS客戶端無法發送有關用戶應使用的外部提供程序進行身份驗證的提示。 這是您可以在授權控制器中輕松處理的內容。 這是一個例子:

public class AuthorizationController : Controller
{
    private readonly IAuthenticationSchemeProvider _authenticationSchemeProvider;
    private readonly SignInManager<ApplicationUser> _signInManager;

    public AuthorizationController(
        IAuthenticationSchemeProvider authenticationSchemeProvider,
        SignInManager<ApplicationUser> signInManager)
    {
        _authenticationSchemeProvider = authenticationSchemeProvider;
        _signInManager = signInManager;
    }

    [HttpGet("~/connect/authorize")]
    public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
    {
        Debug.Assert(request.IsAuthorizationRequest(),
            "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
            "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

        if (!User.Identity.IsAuthenticated)
        {
            // Resolve the optional provider name from the authorization request.
            // If no provider is specified, call Challenge() to redirect the user
            // to the login page defined in the ASP.NET Core Identity options.
            var provider = (string) request.GetParameter("identity_provider");
            if (string.IsNullOrEmpty(provider))
            {
                return Challenge();
            }

            // Ensure the specified provider is supported.
            var schemes = await _authenticationSchemeProvider.GetAllSchemesAsync();
            if (!schemes.Any(scheme => scheme.Name == provider))
            {
                return Challenge();
            }

            // When using ASP.NET Core Identity and its default AccountController,
            // the user must be redirected to the ExternalLoginCallback action
            // before being redirected back to the authorization endpoint.
            var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider,
                Url.Action("ExternalLoginCallback", "Account", new
                {
                    ReturnUrl = Request.PathBase + Request.Path + Request.QueryString
                }));

            return Challenge(properties, provider);
        }

        // ...
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM