You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Web API集成SP发起的SAML 2.0 POST及生成SP元数据求助

Got it, let's walk through how to implement SP-initiated SAML 2.0 POST in a C# Web API and generate valid SP metadata for your clients. I'll start with the core concepts, then dive into actionable code snippets using a battle-tested library to avoid reinventing the wheel.

实现思路概述

SP-initiated SAML 2.0 POST follows this flow:

  1. A user tries to access a protected endpoint in your Web API.
  2. Your API redirects the user to the Identity Provider (IdP) login page with a signed SAML Authentication Request.
  3. After successful login, the IdP sends a SAML Assertion back to your API's Assertion Consumer Service (ACS) endpoint via HTTP POST.
  4. Your API validates the assertion's signature, checks its validity (expiry, issuer, etc.), and creates a local user session (e.g., JWT cookie or token).
  5. The user is redirected to the original protected resource with access granted.

For SP metadata: This is a standardized XML document that tells the IdP how to communicate with your SP—including your entity ID, ACS endpoint URL, signing certificate, and supported algorithms. You'll expose this as a public endpoint for your clients to import into their IdP configuration.

核心步骤详解

We'll use the ITfoxtec.Identity.Saml2 library (the go-to choice for .NET SAML implementations) to handle all the heavy lifting of SAML message serialization, signature validation, and metadata generation.

Step 1: Install the Library

First, add the NuGet package to your project:

# Using .NET CLI
dotnet add package ITfoxtec.Identity.Saml2.AspNetCore

Step 2: Configure SAML Settings

Add your SP and IdP configuration to appsettings.json:

"Saml2Settings": {
  "Issuer": "https://your-sp-api.com/api/saml/metadata", // Unique SP entity ID (usually your metadata endpoint URL)
  "AcsUrl": "https://your-sp-api.com/api/saml/acs", // ACS endpoint where IdP sends assertions
  "SignatureAlgorithm": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
  "Certificate": {
    "FilePath": "Certificates/SP-Signing-Cert.pfx", // Path to your SP's signing certificate
    "Password": "your-cert-password"
  },
  "IdPMetadata": {
    "MetadataUrl": "https://your-client-idp.com/metadata" // Your client's IdP metadata URL
  }
}

Step 3: Register SAML Services in Program.cs

For .NET 6+, wire up the SAML services in your Program.cs:

using ITfoxtec.Identity.Saml2;
using ITfoxtec.Identity.Saml2.MvcCore;

var builder = WebApplication.CreateBuilder(args);

// Bind SAML configuration from appsettings
builder.Services.AddSaml2(options =>
{
    builder.Configuration.GetSection("Saml2Settings").Bind(options);
    options.SignAuthnRequest = true; // Always sign authentication requests for security
});

// Add authentication with SAML2 scheme
builder.Services.AddAuthentication(Saml2Defaults.AuthenticationScheme)
    .AddSaml2();

builder.Services.AddControllers();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthentication(); // Enable authentication middleware
app.UseAuthorization(); // Enable authorization middleware

app.MapControllers();

app.Run();
示例代码实现

Create a SamlController to handle login initiation, ACS callbacks, and metadata generation:

using ITfoxtec.Identity.Saml2;
using ITfoxtec.Identity.Saml2.MvcCore;
using ITfoxtec.Identity.Saml2.Schemas;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

[Route("api/saml")]
[ApiController]
public class SamlController : ControllerBase
{
    private readonly Saml2Configuration _samlConfig;
    private readonly ILogger<SamlController> _logger;

    public SamlController(IOptions<Saml2Configuration> samlConfig, ILogger<SamlController> logger)
    {
        _samlConfig = samlConfig.Value;
        _logger = logger;
    }

    // Initiate SP-initiated SAML login
    [HttpGet("login")]
    public IActionResult Login(string returnUrl = "/api/protected")
    {
        var authnRequest = new Saml2AuthnRequest(_samlConfig, new Saml2PostBinding())
        {
            Destination = _samlConfig.IdPSsoUrl,
            RelayState = returnUrl
        };

        var binding = new Saml2PostBinding();
        binding.SetRelayStateQuery(new Dictionary<string, string> { { "ReturnUrl", returnUrl } });
        
        // Redirect user to IdP login page with signed AuthnRequest
        return binding.Bind(authnRequest).ToActionResult();
    }

    // ACS endpoint: Receive and validate SAML assertion from IdP
    [HttpPost("acs")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Acs()
    {
        var samlResponse = new Saml2AuthnResponse(_samlConfig);

        try
        {
            var binding = new Saml2PostBinding();
            binding.ReadSamlResponse(Request.ToGenericHttpRequest(), samlResponse);

            // Check if the SAML response is successful
            if (samlResponse.Status != Saml2StatusCodes.Success)
            {
                throw new Exception($"SAML authentication failed with status: {samlResponse.Status}");
            }

            // Validate the assertion's signature and create a user session
            samlResponse.CreateSession(HttpContext, claimsTransform: principal =>
            {
                // Add custom claims if needed
                principal.Identities.First().AddClaim(new System.Security.Claims.Claim("api_access", "full"));
                return principal;
            });

            // Redirect back to the original protected resource
            var returnUrl = binding.GetRelayStateQuery()["ReturnUrl"];
            return Redirect(returnUrl);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing SAML ACS request");
            return BadRequest("SAML authentication failed. Please try again.");
        }
    }

    // Expose SP metadata for clients to import into their IdP
    [HttpGet("metadata")]
    public IActionResult Metadata()
    {
        var metadata = new Saml2Metadata(_samlConfig)
        {
            SigningCertificate = _samlConfig.SigningCertificate,
            WantAssertionsSigned = true, // Require IdP to sign assertions for security
            Organization = new Saml2Organization
            {
                Names = new List<Saml2LocalizedName> { new() { Value = "Your Company Name", Lang = "en" } },
                DisplayNames = new List<Saml2LocalizedName> { new() { Value = "Your SP API", Lang = "en" } },
                Urls = new List<Saml2LocalizedUri> { new() { Value = "https://your-sp-api.com", Lang = "en" } }
            }
        };

        return new Saml2MetadataContentResult(metadata);
    }
}

Protected Endpoint Example

Create a protected API endpoint to test the flow:

[Route("api/protected")]
[ApiController]
[Authorize(AuthenticationSchemes = Saml2Defaults.AuthenticationScheme)]
public class ProtectedController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        var userDetails = new
        {
            UserName = User.Identity.Name,
            Claims = User.Claims.Select(c => new { c.Type, c.Value })
        };

        return Ok(new { Message = "Access granted to protected resource", User = userDetails });
    }
}
关键注意事项
  • Certificate Management: Use a valid SSL certificate for signing SAML requests/responses. Share the public key (from your PFX) with your clients so their IdP can verify your signatures.
  • Security Best Practices: Always sign AuthnRequests and require signed assertions. Use HTTPS for all SAML-related endpoints to prevent man-in-the-middle attacks.
  • Metadata Updates: If your client's IdP changes their metadata (e.g., endpoints, certificates), update your IdPMetadata configuration promptly.
  • Error Handling: Add robust error handling in the ACS endpoint to catch invalid signatures, expired assertions, and other common SAML errors.
  • RelayState Validation: Validate the ReturnUrl in the RelayState to prevent open redirect attacks (e.g., check if it's a valid path in your API).

内容的提问来源于stack exchange,提问作者Neet Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:05:04