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:Securityencryption.pfx";
        string encryptionCertificatePassword = "123456";//证书密码

        X509Certificate2 encryptionX509Certificate = new X509Certificate2(encryptionCertificatePath, encryptionCertificatePassword);
        SecurityKey encryptionSecurityKey = new X509SecurityKey(encryptionX509Certificate);

        //验证Issuer的公钥证书(.cer证书文件,只包含公钥,不包含私钥)
        string issuerCertificatePath = @"C:Securityissuer.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 中的用户进行身份验证

原文地址:https://www.cnblogs.com/OpenCoder/p/10627443.html