Azure AD(五)使用多租戶應用程序模式讓任何 Azure Active Directory 用戶登陸

一,引言

距離上次分享關於 「Azure AD" 的知識過去差很少2個多月了, 今天最近恰好也是學習,分享一下關於Azure AD 使用多租戶應用程序模式讓任何 Azure Active Directory 用戶登陸,以前僅僅都是在當初租戶的用戶或者受邀來賓來訪問和使用咱們的api資源的。今天咱們將如下關於只要擁有微軟 的工做/學校帳號的用戶均可以使用咱們受AD保護的 API 資源。接下來就開始咱們今天的分享 html

--------------------我是分割線--------------------git

1,Azure AD(一)入門認識

2,Azure AD(二)調用受Microsoft 標識平臺保護的 ASP.NET Core Web API  上

3,Azure AD(二)調用受Microsoft 標識平臺保護的 ASP.NET Core Web API 下

4,Azure AD(三)知識補充-Azure資源的託管標識

5,Azure AD(四)知識補充-服務主體

6,Azure AD(五)使用多租戶應用程序模式讓任何 Azure Active Directory 用戶登陸

二,正文

1,修改受保護資源的應用的帳號類型

首先咱們登錄Azure Portal 上,而且切換一下當前活動的目錄(也就是當前所在的租戶)github

在以前在AAD中註冊好的應用註冊---」WebApi「,點擊進入WebApi的設置json

 點擊圖中圈中的受支持的帳戶類型---僅個人組織api

 修改 受支持的帳號類型 爲 」任何組合目錄(任何 Azure AD 目錄 - 都租戶)中的帳戶「,點擊 」保存「app

 

咱們使用其餘租戶的帳號登錄認證,提示  當前登錄帳號不在當前登錄的租戶內ide

2,修改代碼配置

微軟官方文檔給出,當使用多租戶模式的時候,post

(1)代碼須要更爲爲向/common 發出請求學習

  在單租戶應用程序中,登陸請求將發送到租戶的登陸終結點。 以 trainingdiscussion.partner.onmschina.cn 爲例,終結點將是:https://login.chinacloudapi.cn/trainingdiscussion.partner.onmschina.cn。 發送到租戶終結點的請求可讓該租戶中的用戶(或來賓)登陸該租戶中的應用程序。測試

使用多租戶應用程序時,應用程序事先並不知道用戶來自哪一個租戶,所以沒法將請求發送到租戶的終結點。 取而代之的是,請求將發送到在全部 Azure AD 租戶之間多路複用的終結點:https://login.chinacloudapi.cn/common

  當 Microsoft 標識平臺在 /common 終結點上收到請求時,會使用戶登陸,於是能夠發現用戶來自哪一個租戶。 /Common 終結點可與 Azure AD 支持的全部身份驗證協議配合使用: OpenID Connect、OAuth 2.0、SAML 2.0 和 WS 聯合身份驗證。

/common 終結點不是租戶,也不是頒發者,而只是一個多路複用器。 使用 /common 時,須要更新應用程序中用於驗證令牌的邏輯。而後,對應用程序作出的登陸響應會包含表明該用戶的令牌。 令牌中的頒發者值告知應用程序該用戶來自哪一個租戶。 從 /common 終結點返回響應時,令牌中的頒發者值將與用戶的租戶相對應。

(2)將代碼更新爲處理多個頒發者值

單租戶應用程序一般採用相似於下面的終結點值:https://login.chinacloudapi.cn/trainingdiscussion.partner.onmschina.cn

並使用該值構造元數據 URL(在本例中爲 OpenID Connect),例如:https://login.chinacloudapi.cn/trainingdiscussion.partner.onmschina.cn/.well-known/openid-configuration

如下載用於驗證令牌的兩項關鍵信息:租戶的簽名密鑰和頒發者值。 每一個 Azure AD 租戶使用如下格式的惟一頒發者值:https://sts.chinacloudapi.cn/53359126-8bcf-455d-a934-5fe72d349207/

下圖中,是我當前AAD 租戶中註冊的 Web Api  的OpenID Connect 元數據文檔

Authentication 配置

services.AddAuthentication("Bearer")
                .AddJwtBearer(o =>
                {
                    o.Audience = Appsettings.app(new string[] { "AzureAD", "ClientId" });
                    o.RequireHttpsMetadata = false;
                    o.SaveToken = true;
                    o.Authority = Appsettings.app(new string[] { "AzureAD", "Authority" });
                    o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = Appsettings.app(new string[] { "AzureAD", "Issuer" }),
                        ValidateLifetime = true,
                    };
                });

Swagger服務的配置

 services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT受權(數據將在請求頭中進行傳輸) 直接在下框中輸入Bearer {token}(注意二者之間是一個空格)\"",
                    Type = SecuritySchemeType.OAuth2,
                    In = ParameterLocation.Header,//jwt默認存放Authorization信息的位置(請求頭中)
                    Flows = new OpenApiOAuthFlows()
                    {
                        Implicit = new OpenApiOAuthFlow
                        {
                            //AuthorizationUrl = new Uri($"https://login.chinacloudapi.cn/{ Appsettings.app(new string[] { "AzureAD", "TenantId" })}/oauth2/authorize")
                            AuthorizationUrl = new Uri($"https://login.chinacloudapi.cn/common/oauth2/authorize")
                        }
                    }
                });
                // 在header中添加token,傳遞到後臺
                c.OperationFilter<SecurityRequirementsOperationFilter>();
            });

開啓中間件

#region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根據版本名稱倒序 遍歷展現
                var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
                c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"{ApiName} v1");

                c.OAuthClientId(Appsettings.app(new string[] { "Swagger", "ClientId" }));
                //c.OAuthClientSecret(Appsettings.app(new string[] { "Swagger", "ClientSecret" }));
                c.OAuthRealm(Appsettings.app(new string[] { "AzureAD", "ClientId" }));
                c.OAuthAppName("My API V1");
                c.OAuthScopeSeparator(" ");
                c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>() { { "resource", Appsettings.app(new string[] { "AzureAD", "ClientId" }) } });
            });
            #endregion
            IdentityModelEventSource.ShowPII = true; // here
            app.UseAuthentication();

完整代碼:

public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public IConfiguration Configuration { get; }

        public IWebHostEnvironment Environment { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(new Appsettings(Environment.ContentRootPath));


            //services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
            //    .AddAzureADBearer(options => Configuration.Bind("AzureAd", options));

            services.AddAuthentication("Bearer")
                .AddJwtBearer(o =>
                {
                    o.Audience = Appsettings.app(new string[] { "AzureAD", "ClientId" });
                    o.RequireHttpsMetadata = false;
                    o.SaveToken = true;
                    o.Authority = Appsettings.app(new string[] { "AzureAD", "Authority" });
                    o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        ValidateIssuerSigningKey = false,
                        ValidIssuer = Appsettings.app(new string[] { "AzureAD", "Issuer" }),
                        ValidateLifetime = true,

                    };
                });

            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                {
                    Description = "JWT受權(數據將在請求頭中進行傳輸) 直接在下框中輸入Bearer {token}(注意二者之間是一個空格)\"",
                    Type = SecuritySchemeType.OAuth2,
                    In = ParameterLocation.Header,//jwt默認存放Authorization信息的位置(請求頭中)
                    Flows = new OpenApiOAuthFlows()
                    {
                        Implicit = new OpenApiOAuthFlow
                        {
                            //AuthorizationUrl = new Uri($"https://login.chinacloudapi.cn/{ Appsettings.app(new string[] { "AzureAD", "TenantId" })}/oauth2/authorize")
                            AuthorizationUrl = new Uri($"https://login.chinacloudapi.cn/common/oauth2/authorize")
                        }
                    }
                });
                // 在header中添加token,傳遞到後臺
                c.OperationFilter<SecurityRequirementsOperationFilter>();
            });

            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            #region Swagger
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                //根據版本名稱倒序 遍歷展現
                var ApiName = Appsettings.app(new string[] { "Startup", "ApiName" });
                c.SwaggerEndpoint($"/swagger/v1/swagger.json", $"{ApiName} v1");

                c.OAuthClientId(Appsettings.app(new string[] { "Swagger", "ClientId" }));
                //c.OAuthClientSecret(Appsettings.app(new string[] { "Swagger", "ClientSecret" }));
                c.OAuthRealm(Appsettings.app(new string[] { "AzureAD", "ClientId" }));
                c.OAuthAppName("My API V1");
                c.OAuthScopeSeparator(" ");
                c.OAuthAdditionalQueryStringParams(new Dictionary<string, string>() { { "resource", Appsettings.app(new string[] { "AzureAD", "ClientId" }) } });
            });
            #endregion
            IdentityModelEventSource.ShowPII = true; // here
            app.UseAuthentication();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
Startup
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AzureAd": {
      "Instance": "https://login.chinacloudapi.cn/common",
      "Domain": "trainingdiscussion.partner.onmschina.cn",
      "TenantId": "common",
      "ClientId": "f38ec09d-203e-4b2d-a1c1-faf76a608528",
"CallbackPath": "/signin-oidc",
    "Authority": "https://login.chinacloudapi.cn/organizations/v2.0/",
    "Issuer": "https://sts.chinacloudapi.cn/53359126-8bcf-455d-a934-5fe72d349207/"
    },
    "Swagger": {
      "ClientId": "62ca9f31-585c-4d28-84b6-25fb7855aed0",
      "ClientSecret": "" //  ?fxV/=/pwlRjwQgoIdLRlPNlWBBQ8939
    }
}
application

3,運行項目,進行測試

 咱們進行測試 order 接口,提示 返回碼 401,無權限。

咱們點擊頁面上的 」Authorize「 進行驗證

 這裏,咱們輸入其餘azure租戶的用戶的帳號信息進行登錄驗證(由於這號牽扯我的隱私,因此目前不展現),點擊下一步

 輸入 帳號密碼信息,點擊登錄

 登錄驗證經過後,咱們再次進行驗證操做

 咱們再次進行測試,ok,成功

🎉🎉🎉🎉🎉!!! 成功!,你們能夠都試試哈

三,結尾

今天的文章大概介紹了多租戶模式登錄/訪問咱們的受Azure AD保護的api資源,以及經過 Swagger中使用隱式受權模式來訪問Api資源。

代碼稍等,我會整理一下,上傳到github中

做者:Allen 

版權:轉載請在文章明顯位置註明做者及出處。如發現錯誤,歡迎批評指正。

相關文章
相關標籤/搜索