簡體   English   中英

單租戶應用程序需要通過 OpenId Owin 動態支持來自多租戶提供商的 SSO

[英]Single Tenant Application needs to support SSO from a multi-tenant provider dynamically with OpenId Owin

我正在嘗試使用 OpenId 對動態授權 URL 進行身份驗證。 存在未知數量的不同{n-tenant}.identityProvider.com授權 URL。 因此,我需要能夠通過用戶訪問我的應用程序的n-tenant ,並在用戶嘗試登錄時動態配置UseOpenIdConnectAuthentication

這意味着我在啟動時不知道授權 URL 是什么,因為我不知道要注冊哪個n-tenant 我只會在租戶嘗試訪問我的應用程序的登錄端點后才知道Authrity URL 是什么,因為它在 URL 中有一個n-tenant值。

我嘗試使用RedirectToIdentityProvider通知重新配置n.Options.Authority ,但這不起作用。 此外,在啟動時省略Authority配置會導致異常。

如果我對特定的n-tenant進行硬編碼,則下面的代碼可以正常工作。 但是,我無法弄清楚如何動態配置OpenIdConnectAuthenticationOptions以在其權限 URL 中使用動態n-tenant值。

請注意,所有n-tenant的 ClientId 和 ClientSecret 都是相同的。 只有端點需要是動態的。

我正在使用帶有 .NET Framework 4.8 的 ASP.NET 表單

在此處輸入圖像描述

啟動.cs

using IdentityModel.Client;
using Microsoft.AspNet.Identity;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin;
using Microsoft.Owin.Host.SystemWeb;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Security.Claims;

[assembly: OwinStartup(typeof(MyApplication.Startup))]
namespace MyApplication
{
    public class Startup
    {
        private readonly string _clientId = "CLIENT_ID";
        private readonly string _clientSecret = "CLIENT_SECRET";

        private readonly string _redirectUri = "https://myapplication.com/{n-tenant}/oidc-callback";
        private readonly string _authority = "https://identityprovider.com/{n-tenant}/";
        

        public void Configuration(IAppBuilder app)
        {
            JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

            ConfigureAuth(app);
        }

        public void ConfigureAuth(IAppBuilder app)
        {
            app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());


            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
            {
                ClientId = _clientId,
                ClientSecret = _clientSecret,
                Authority = _authority,
                RedirectUri = _redirectUri,
                ResponseType = OpenIdConnectResponseType.Code,
                Scope = OpenIdConnectScope.OpenId,
                TokenValidationParameters = new TokenValidationParameters { NameClaimType = "sub" },
                CallbackPath = new PathString("/{n-tenant}/oidc-callback"),
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    RedirectToIdentityProvider = async n =>
                    {
                    },
                    AuthorizationCodeReceived = async n =>
                    {
                        using (var client = new HttpClient())
                        {

                            var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest
                            {
                                Address = $"{_authority}/connect/token",
                                ClientId = _clientId,
                                ClientSecret = _clientSecret,
                                Code = n.Code,
                                RedirectUri = _redirectUri
                            });

                            if (tokenResponse.IsError)
                            {
                                throw new Exception(tokenResponse.Error);
                            }

                            n.TokenEndpointResponse = new OpenIdConnectMessage(tokenResponse.Raw);
                        }

                    }
                },
                
            });
        }
}

很難發布一個完全可以幫助您解決問題的答案,因為檢查它是否有效的唯一方法是重現您可能不可能的整個環境。

很難為這些庫找到任何類型的文檔,但通常當我處理任何 OAuth 或 OpenIDConnect 流程時,我會使用這些存儲庫: KatanaIdentityModel

我認為您關於使用RedirectToIdentityProvider的想法是正確的。 這是在將用戶重定向到您的身份服務器之前調用的 Katana 代碼中的位置。 因此,您可以修改在構建 Url 時使用的參數。 你可以像這樣開始你的 lambda:

RedirectToIdentityProvider = async n =>
{
   if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectRequestType.Authentication)
   {
      n.ProtocolMessage.Parameters["redirect_uri"] = //your whole url here

我認為調試這個地方或在某處記錄你在那個上下文中的參數也是一個好主意。 因為我相信你應該有一個類似於IssuerAddress的參數或屬性。 這應該是您的身份服務器的地址 - 您也可以修改它。

如果您正確設置這些值,不幸的是整個流程仍然無法正常工作。 這是因為在中間件處理程序中使用CallbackPath來識別到達您的應用程序的請求是否是 OAuth 流的一部分。 您可以在此處找到此代碼。 否則,您的AuthorizationCodeReceived處理程序將不會被調用。

所以現在的問題是 - 你真的需要單獨的CallbackPath 根據您的問題,您說應用程序將設置像"https://myapplication.com/{n-tenant}/oidc-callback"這樣的回調,但實際上發生的是中間件獲取代碼(在用戶登錄后) 並在反向通道(服務器到服務器請求)中將其交換為 access_token。 在默認流程中,令牌存儲在瀏覽器 cookie 中 - 在您的場景中,您的所有應用程序看起來都共享相同的 cookie(托管在同一個域上)。 所以很難說用戶登錄后你的預期行為是什么。

如果在您的場景中這種分離是“必須的”,那么我能看到的唯一路徑就是使用 Katana 存儲庫代碼並制作您自己的OpenidConnectAuthenticationHandler實現。

暫無
暫無

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

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