ASP.NET Core如何使用WSFederation身份认证集成ADFS
如果要在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 中的用户进行身份验证