如何通过外部API登录并生成JWT?ASP.NET Core对接实现咨询
Got it, let's walk through how to properly integrate your ASP.NET Core app with that external JWT-based login API. Your initial code snippet is a good start, but we can expand it to make it robust, production-ready, and aligned with ASP.NET Core's authentication best practices.
First, you need to set up authentication services in your app's startup logic. We'll use cookie authentication to maintain the user session (since you're calling SignInAsync) and JWT validation to ensure the external token is legitimate.
var builder = WebApplication.CreateBuilder(args); // Add authentication services builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/Account/Login"; options.ExpireTimeSpan = TimeSpan.FromHours(2); // Match your external JWT's expiry if needed }) .AddJwtBearer(options => { // Configure JWT validation to match the external API's token settings options.Authority = "https://your-external-api-domain.com"; // Use this if the API uses OAuth2/OIDC options.Audience = "your-apps-audience-identifier"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, // If you don't use Authority, hardcode these values instead: // ValidIssuer = "https://your-external-api-domain.com", // ValidAudience = "your-apps-audience-identifier", // IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"])) }; }); builder.Services.AddControllersWithViews(); // Register your external login service with HttpClient (best practice for API calls) builder.Services.AddHttpClient<IExternalLoginService, ExternalLoginService>(); var app = builder.Build(); // Configure middleware pipeline if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // Critical: Add authentication and authorization middleware in this order app.UseAuthentication(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
Expand your login logic to handle validation, token parsing, and proper session management. We'll add model validation, error handling, and claims extraction from the external JWT.
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Mvc; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; public class AccountController : Controller { private readonly IExternalLoginService _externalLoginService; public AccountController(IExternalLoginService externalLoginService) { _externalLoginService = externalLoginService; } [HttpGet] public IActionResult Login(string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Login(string userName, string password, string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; returnUrl ??= Url.Content("~/"); if (!ModelState.IsValid) { return View(); } bool loginSuccess = false; ExternalLoginResponse loginResult = null; try { // Call the external API to validate credentials and retrieve the JWT loginResult = await _externalLoginService.LoginAsync( "https://your-external-api.com/login-endpoint", userName, password); if (loginResult == null || string.IsNullOrWhiteSpace(loginResult.Token)) { ModelState.AddModelError(string.Empty, "Invalid username or password."); return View(); } // Parse the JWT to extract user claims for the session var tokenHandler = new JwtSecurityTokenHandler(); var jwtToken = tokenHandler.ReadJwtToken(loginResult.Token); var claims = jwtToken.Claims.ToList(); // Optional: Add custom claims specific to your app claims.Add(new Claim(ClaimTypes.Name, userName)); // Create a claims identity for cookie authentication var claimsIdentity = new ClaimsIdentity( claims, CookieAuthenticationDefaults.AuthenticationScheme); // Set session properties (match JWT expiry, enable "remember me" if needed) var authProps = new AuthenticationProperties { IsPersistent = false, // Toggle this for "Remember Me" functionality ExpiresUtc = jwtToken.ValidTo }; // Sign the user into the app's session await HttpContext.SignInAsync( CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity), authProps); loginSuccess = true; } catch (HttpRequestException) { // Handle external API connectivity issues ModelState.AddModelError(string.Empty, "Could not connect to the login service. Please try again later."); } catch (Exception) { // Catch-all for unexpected errors ModelState.AddModelError(string.Empty, "An unexpected error occurred. Please try again."); } if (loginSuccess) { return LocalRedirect(returnUrl); } // If we reach here, login failed return View(); } [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); return RedirectToAction(nameof(HomeController.Index), "Home"); } } // Model to map the external API's login response public class ExternalLoginResponse { public string Token { get; set; } // Add other fields from the API response (e.g., RefreshToken, ExpiryInMinutes) } // Interface for the external login service public interface IExternalLoginService { Task<ExternalLoginResponse> LoginAsync(string loginUrl, string userName, string password); } // Implementation of the external login service public class ExternalLoginService : IExternalLoginService { private readonly HttpClient _httpClient; public ExternalLoginService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<ExternalLoginResponse> LoginAsync(string loginUrl, string userName, string password) { var loginPayload = new { UserName = userName, Password = password }; var response = await _httpClient.PostAsJsonAsync(loginUrl, loginPayload); // Throw an error if the API returns a non-success status code response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<ExternalLoginResponse>(); } }
- Token Validation: Always validate the external JWT in your app to prevent tampered or expired tokens from being used. The JWT Bearer middleware handles this automatically.
- Error Handling: Specific exception types (like
HttpRequestException) let you give users meaningful feedback instead of generic errors. - HttpClient Usage: Using
AddHttpClientensures you follow best practices for external API calls (avoids socket exhaustion, enables retries, etc.). - Claims Management: Extracting claims from the JWT lets you use ASP.NET Core's built-in authorization features (e.g.,
[Authorize]attributes, role-based access).
内容的提问来源于stack exchange,提问作者Mohammed Qamhawi

