如果要在ASP.NET Core項目中使用WSFederation身份認證,首先需要在項目中引入NuGet包:
Microsoft.AspNetCore.Authentication.WsFederation
不使用證書驗證Issuer,也不使用證書加密ADFS的認證信息
如果你的ASP.NET Core項目,不需要證書來驗證ADFS的Issuer信息,也不需要證書來加密ADFS的認證信息,那么只需要在ASP.NET Core的Startup類中設置和啟用WsFederation中間件即可,代碼如下所示:
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { // MetadataAddress represents the Active Directory instance used to authenticate users. options.MetadataAddress = "https://www.contoso.com/FederationMetadata/2007-06/FederationMetadata.xml"; // Wtrealm is the app's identifier in the Active Directory instance. options.Wtrealm = "https://localhost:44307/"; //用戶在ADFS登錄頁成功登錄后,跳轉回ASP.NET Core站點的URL地址 options.Wreply = "https://localhost:44307/signin"; //用於解析從ADFS登錄頁傳回ASP.NET Core站點的認證信息的URL地址,ASP.NET Core會使用該URL地址將ADFS認證信息解析為Claim,並存儲在Cookie中 options.CallbackPath = "/signin"; //設置WsFederation認證中間件與遠程ADFS認證服務器的網絡通信連接超時時間為1分鍾 options.BackchannelTimeout = TimeSpan.FromMinutes(1); //設置完成整個ADFS認證流程的超時時間為15分鍾 options.RemoteAuthenticationTimeout = TimeSpan.FromMinutes(15); }) .AddCookie(); services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseAuthentication(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
上面的代碼中有兩個屬性需要注意:
- options.Wreply,是用戶在ADFS登錄頁成功登錄后,跳轉回ASP.NET Core站點的URL地址
- options.CallbackPath,是用於解析從ADFS登錄頁傳回ASP.NET Core站點的認證信息的URL地址,ASP.NET Core會使用該URL地址將ADFS認證信息解析為Claim,並存儲在用戶瀏覽器的Cookie中
因此options.CallbackPath的地址必須要和options.Wreply的地址保持一致,例如上面我們設置了options.Wreply為"https://localhost:44307/signin",那么options.CallbackPath必須是options.Wreply中以"/"開頭的絕對路徑URL地址,也就是"/signin"(注意options.CallbackPath不能設置為帶主機域名的完全URL地址,只能是以"/"開頭的絕對路徑URL地址)。這樣當用戶從ADFS登錄頁成功登錄后,跳轉回我們的ASP.NET Core站點時,ASP.NET Core才能成功解析ADFS的認證信息。
上面代碼中還有兩個關於超時的屬性:
- options.BackchannelTimeout,是WsFederation認證中間件與遠程ADFS認證服務器的網絡通信連接超時時間
- options.RemoteAuthenticationTimeout,是完成整個ADFS認證流程的超時時間
這兩個超時屬性如果時間設置得太小,可能會造成認證超時而拋出異常,實際上這兩個屬性屬於RemoteAuthenticationOptions類,WsFederationOptions類繼承於RemoteAuthenticationOptions類,所有繼承RemoteAuthenticationOptions的類都可以設置這兩個超時屬性。
使用證書驗證Issuer,並使用證書加密ADFS的認證信息
由於接下來本文中我們要在WSFederation認證中用到X509證書,所以你需要先申請一個.pfx證書文件,用於加密和解密ADFS的認證信息,將該.pfx文件使用certlm.msc命令,來導入ASP.NET Core站點服務器certlm中的"Trusted Root Certification Authorities"和"Personal"文件夾中,如下所示:
運行certlm.msc命令:
在左邊列表中,找到"Trusted Root Certification Authorities"文件夾,然后在下面的"Certificates"文件夾上點擊鼠標右鍵,通過右鍵菜單選擇"All Tasks",然后點擊"Import":
然后通過導入向導,導入你的.pfx證書文件到certlm中"Trusted Root Certification Authorities"文件夾:
再在certlm.msc左邊列表中,找到"Personal"文件夾,然后在下面的"Certificates"文件夾上點擊鼠標右鍵,通過右鍵菜單選擇"All Tasks",然后點擊"Import":
然后同樣通過導入向導,導入你的.pfx證書文件到certlm中"Personal"文件夾:
接下來,你還要確保服務器IIS中,已經在ASP.NET Core項目站點使用的應用程序池上,設置了Load User Profile屬性為True。
然后按照下面的代碼,在ASP.NET Core的Startup類中設置和啟用WsFederation中間件:
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(sharedOptions => { sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; sharedOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme; }) .AddWsFederation(options => { // MetadataAddress represents the Active Directory instance used to authenticate users. options.MetadataAddress = "https://www.contoso.com/FederationMetadata/2007-06/FederationMetadata.xml"; // Wtrealm is the app's identifier in the Active Directory instance. options.Wtrealm = "https://localhost:44307/"; //用戶在ADFS登錄頁成功登錄后,跳轉回ASP.NET Core站點的URL地址 options.Wreply = "https://localhost:44307/signin"; //用於解析從ADFS登錄頁傳回ASP.NET Core站點的認證信息的URL地址,ASP.NET Core會使用該URL地址將ADFS認證信息解析為Claim,並存儲在Cookie中 options.CallbackPath = "/signin"; //設置WsFederation認證中間件與遠程ADFS認證服務器的網絡通信連接超時時間為1分鍾 options.BackchannelTimeout = TimeSpan.FromMinutes(1); //設置完成整個ADFS認證流程的超時時間為15分鍾 options.RemoteAuthenticationTimeout = TimeSpan.FromMinutes(15); //ADFS認證信息的加密和解密證書(.pfx證書文件,既包含公鑰,又包含私鑰) string encryptionCertificatePath = @"C:\Security\encryption.pfx"; string encryptionCertificatePassword = "123456";//證書密碼 X509Certificate2 encryptionX509Certificate = new X509Certificate2(encryptionCertificatePath, encryptionCertificatePassword); SecurityKey encryptionSecurityKey = new X509SecurityKey(encryptionX509Certificate); //驗證Issuer的公鑰證書(.cer證書文件,只包含公鑰,不包含私鑰) string issuerCertificatePath = @"C:\Security\issuer.cer"; X509Certificate2 issuerX509Certificate = new X509Certificate2(issuerCertificatePath); SecurityKey issuerSecurityKey = new X509SecurityKey(issuerX509Certificate); options.TokenValidationParameters = new TokenValidationParameters { AuthenticationType = CookieAuthenticationDefaults.AuthenticationScheme, TokenDecryptionKey = encryptionSecurityKey,//設置解密ADFS認證信息的證書 IssuerSigningKey = issuerSecurityKey,//設置驗證Issuer的公鑰證書 ValidateIssuerSigningKey = true, ValidateActor = false, ValidateTokenReplay = false, ValidateAudience = false, ValidateLifetime = false, ValidateIssuer = true }; }) .AddCookie(); services.AddMvc(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseBrowserLink(); app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseAuthentication(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); }
注意上面代碼中:
- encryption.pfx證書文件,既包含公鑰,又包含私鑰,它用於在ADFS登錄頁上加密ADFS認證信息,並且在我們的ASP.NET Core站點中解密ADFS認證信息。
- issuer.cer證書文件,只包含公鑰,不包含私鑰,它用於驗證ADFS認證信息的頒發者(Issuer)的身份是否屬實。
參考文獻:
使用 WS 聯合身份驗證在 ASP.NET Core 中的用戶進行身份驗證