ASP.NET Core MVC项目集成Web API实现JWT认证授权
ASP.NET 6 Core MVC + Web API JWT认证与授权实现方案
一、Web API端配置与登录接口实现
1. 配置JWT参数
在Web API项目的appsettings.json中添加JWT核心配置:
"Jwt": { "Issuer": "YourApiIssuer", "Audience": "YourMvcClient", "SecretKey": "YourStrongSecretKeyAtLeast16CharsLong", "TokenExpiresInMinutes": 60 }
2. 注册JWT认证服务
在Program.cs中配置认证与授权中间件:
var builder = WebApplication.CreateBuilder(args); // 注册JWT认证 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecretKey"])) }; }); builder.Services.AddAuthorization(); // 注册其他服务(如DbContext、Identity等) var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
3. 实现真实登录验证与令牌生成
创建AuthController,基于真实用户信息验证并生成JWT:
[ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly UserManager<IdentityUser> _userManager; private readonly IConfiguration _configuration; public AuthController(UserManager<IdentityUser> userManager, IConfiguration configuration) { _userManager = userManager; _configuration = configuration; } [HttpPost("login")] public async Task<IActionResult> Login([FromBody] LoginRequest request) { // 验证用户账号密码 var user = await _userManager.FindByNameAsync(request.Username); if (user == null || !await _userManager.CheckPasswordAsync(user, request.Password)) { return Unauthorized("用户名或密码错误"); } // 生成用户身份Claims var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Name, user.UserName) }; // 添加角色信息(若启用角色授权) var roles = await _userManager.GetRolesAsync(user); claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role))); // 生成JWT令牌 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["Jwt:TokenExpiresInMinutes"])), signingCredentials: creds); return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token), Expiration = token.ValidTo }); } public class LoginRequest { public string Username { get; set; } public string Password { get; set; } } }
注:若未使用ASP.NET Identity,可替换为自定义用户表的验证逻辑,核心是基于真实用户验证结果生成令牌,而非硬编码。
二、MVC端调用登录接口获取JWT令牌
1. 创建登录ViewModel
public class LoginViewModel { [Required] public string Username { get; set; } [Required] [DataType(DataType.Password)] public string Password { get; set; } }
2. 实现登录页面与API调用逻辑
在MVC的AccountController中处理登录请求,调用Web API获取令牌:
public class AccountController : Controller { private readonly HttpClient _httpClient; public AccountController(HttpClient httpClient) { _httpClient = httpClient; _httpClient.BaseAddress = new Uri("https://your-api-base-url/"); } [HttpGet] public IActionResult Login() { return View(); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel model) { if (!ModelState.IsValid) { return View(model); } // 发送登录请求到API var loginRequest = new { Username = model.Username, Password = model.Password }; var response = await _httpClient.PostAsJsonAsync("api/auth/login", loginRequest); if (!response.IsSuccessStatusCode) { ModelState.AddModelError(string.Empty, "登录失败,请检查用户名或密码"); return View(model); } // 解析令牌并存储到Session(推荐用HttpOnly Cookie增强安全性) var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>(); HttpContext.Session.SetString("JwtToken", tokenResponse.Token); return RedirectToAction("Index", "Home"); } private class TokenResponse { public string Token { get; set; } public DateTime Expiration { get; set; } } }
同时在MVC项目Program.cs中启用Session并注册HttpClient:
builder.Services.AddHttpClient(); builder.Services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(60); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); var app = builder.Build(); app.UseSession(); // 其他中间件配置
三、MVC端复用JWT令牌调用受保护API
1. 封装带令牌的HttpClient
创建自定义HttpClient服务,自动注入JWT令牌:
public class ApiHttpClient { private readonly HttpClient _httpClient; private readonly IHttpContextAccessor _httpContextAccessor; public ApiHttpClient(HttpClient httpClient, IHttpContextAccessor httpContextAccessor) { _httpClient = httpClient; _httpClient.BaseAddress = new Uri("https://your-api-base-url/"); _httpContextAccessor = httpContextAccessor; } public async Task<T> GetAsync<T>(string url) { var token = _httpContextAccessor.HttpContext.Session.GetString("JwtToken"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await _httpClient.GetAsync(url); HandleUnauthorized(response); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<T>(); } // 同理封装PostAsync、PutAsync等方法 private void HandleUnauthorized(HttpResponseMessage response) { if (response.StatusCode == HttpStatusCode.Unauthorized) { _httpContextAccessor.HttpContext.Session.Remove("JwtToken"); throw new UnauthorizedAccessException("令牌已过期,请重新登录"); } } }
在Program.cs中注册该服务:
builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<ApiHttpClient>();
2. 在MVC控制器中调用受保护API
public class HomeController : Controller { private readonly ApiHttpClient _apiHttpClient; public HomeController(ApiHttpClient apiHttpClient) { _apiHttpClient = apiHttpClient; } public async Task<IActionResult> Index() { var data = await _apiHttpClient.GetAsync<List<YourBusinessModel>>("api/protected-resource"); return View(data); } }
3. 处理令牌过期
在MVC全局异常过滤器中捕获UnauthorizedAccessException,跳转至登录页:
public class GlobalExceptionFilter : IExceptionFilter { public void OnException(ExceptionContext context) { if (context.Exception is UnauthorizedAccessException) { context.Result = new RedirectToActionResult("Login", "Account", null); context.ExceptionHandled = true; } } }
在Program.cs中注册过滤器:
builder.Services.AddControllersWithViews(options => { options.Filters.Add<GlobalExceptionFilter>(); });
内容的提问来源于stack exchange,提问作者Parthib Sarkar
相关产品推荐
相关产品推荐

