能否通过AD FS SAML实现本地.NET Core控制台应用认证到AWS Cognito?
Absolutely! It’s totally feasible to authenticate to AWS Cognito using AD FS SAML from a local .NET Core console application. Your existing code uses SRP (Secure Remote Password) auth with Cognito’s native users, but for SAML auth via AD FS, we’ll need to adapt the flow since it relies on redirecting the user to AD FS for authentication (even in a console app context).
Prerequisites First
Before writing code, make sure your AWS Cognito setup is ready:
- You’ve added AD FS as a SAML identity provider (IdP) in your Cognito user pool. Import AD FS’s metadata XML, configure attribute mappings (e.g., map AD FS’s
NameIDto Cognito’susername), and give the IdP a recognizable name (likeADFS). - You’ve created a Cognito app client that supports the Authorization Code Flow (with PKCE enabled, since console apps are public clients and can’t securely store client secrets).
- You’ve set a valid redirect URI for the app client (e.g.,
http://localhost:5000/callback– we’ll listen on this port locally).
Step-by-Step Implementation
Here’s how to implement this in your .NET Core console app:
1. Setup Dependencies
Ensure you have these NuGet packages installed:
Install-Package AWSSDK.CognitoIdentityProvider Install-Package System.Net.Http
2. Implement the Authentication Flow
Unlike SRP auth (which is purely programmatic), SAML auth requires user interaction via a browser to complete AD FS’s login. We’ll use a local HTTP listener to capture the authorization code after the user logs in.
using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; using System.Collections.Generic; using System.Text.Json; using System.Security.Cryptography; using System.Text; namespace CognitoAdfsConsoleAuth { class Program { // Replace these with your actual values private const string UserPoolId = "your-user-pool-id"; private const string ClientId = "your-client-id"; private const string CognitoDomain = "your-cognito-domain-prefix.auth.region.amazoncognito.com"; private const string RedirectUri = "http://localhost:5000/callback"; private const string IdentityProvider = "ADFS"; // Name of your AD FS IdP in Cognito static async Task Main(string[] args) { // Generate PKCE code verifier and challenge (required for public clients) var codeVerifier = GenerateRandomCodeVerifier(); var codeChallenge = GenerateCodeChallenge(codeVerifier); // Build the Cognito authorization URL var authUrl = $"https://{CognitoDomain}/oauth2/authorize?" + $"client_id={ClientId}" + $"&response_type=code" + $"&scope=openid+email" + $"&redirect_uri={Uri.EscapeDataString(RedirectUri)}" + $"&identity_provider={IdentityProvider}" + $"&code_challenge={codeChallenge}" + $"&code_challenge_method=S256"; // Open the auth URL in the user's default browser Console.WriteLine("Opening browser for AD FS authentication..."); System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(authUrl) { UseShellExecute = true }); // Start a local HTTP listener to capture the callback with the authorization code using var listener = new HttpListener(); listener.Prefixes.Add(RedirectUri + "/"); listener.Start(); Console.WriteLine($"Waiting for authentication callback on {RedirectUri}..."); var context = await listener.GetContextAsync(); var code = context.Request.QueryString["code"]; if (string.IsNullOrEmpty(code)) { Console.WriteLine("Authorization failed: No code received."); return; } // Send a response to the browser to close the tab var responseString = "<html><body>Authentication successful! You can close this tab now.</body></html>"; var buffer = Encoding.UTF8.GetBytes(responseString); context.Response.ContentLength64 = buffer.Length; var output = context.Response.OutputStream; await output.WriteAsync(buffer, 0, buffer.Length); output.Close(); listener.Stop(); // Exchange the authorization code for tokens var tokenResponse = await ExchangeCodeForTokens(code, codeVerifier); Console.WriteLine($"Successfully authenticated!"); Console.WriteLine($"ID Token: {tokenResponse.IdToken}"); Console.WriteLine($"Access Token: {tokenResponse.AccessToken}"); } private static async Task<TokenResponse> ExchangeCodeForTokens(string code, string codeVerifier) { using var httpClient = new HttpClient(); var requestContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("grant_type", "authorization_code"), new KeyValuePair<string, string>("client_id", ClientId), new KeyValuePair<string, string>("code", code), new KeyValuePair<string, string>("redirect_uri", RedirectUri), new KeyValuePair<string, string>("code_verifier", codeVerifier) }); var tokenEndpoint = $"https://{CognitoDomain}/oauth2/token"; var response = await httpClient.PostAsync(tokenEndpoint, requestContent); response.EnsureSuccessStatusCode(); var tokenJson = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize<TokenResponse>(tokenJson); } // Helper methods for PKCE private static string GenerateRandomCodeVerifier() { var randomBytes = new byte[32]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomBytes); return Convert.ToBase64String(randomBytes) .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); } private static string GenerateCodeChallenge(string codeVerifier) { using var sha256 = SHA256.Create(); var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier)); return Convert.ToBase64String(challengeBytes) .Replace('+', '-') .Replace('/', '_') .TrimEnd('='); } } // Helper class to deserialize token response public class TokenResponse { public string IdToken { get; set; } public string AccessToken { get; set; } public string RefreshToken { get; set; } public int ExpiresIn { get; set; } public string TokenType { get; set; } } }
Key Differences from Your SRP Code
- Your existing SRP flow authenticates directly with Cognito using a native user’s credentials. The SAML flow delegates authentication to AD FS, so we need to redirect the user to AD FS’s login page.
- PKCE is required for public clients (like console apps) to secure the authorization code exchange, since we can’t store a client secret safely.
- After authentication, we get the same types of tokens (ID, Access, Refresh) as with SRP, so you can use them with Cognito APIs or AWS services just like before.
Troubleshooting Tips
- If you get an "invalid redirect URI" error, double-check that the redirect URI in your code matches exactly what’s configured in your Cognito app client.
- Ensure your AD FS IdP is correctly configured in Cognito – test the SAML flow via the Cognito hosted UI first to confirm it works before adding the console app code.
- If the AD FS login page doesn’t load, verify that your Cognito domain is active and that the IdP name in the
identity_providerparameter matches the name you gave your AD FS IdP in Cognito.
内容的提问来源于stack exchange,提问作者beewest

