ASP.NET Core 6 MVC中如何在请求头添加JWT令牌并调用鉴权API
ASP.NET Core MVC调用JWT授权API的问题解决指南
1. 解决IHttpClientFactory无法解析的异常
这个异常是因为你没有在服务容器中注册IHttpClientFactory,只需在Program.cs中添加注册代码:
// 在builder.Services.AddControllersWithViews()之前或之后添加 builder.Services.AddHttpClient();
然后在控制器的构造函数中注入该服务(确保你没有手动实例化控制器,而是依赖框架注入):
private readonly IHttpClientFactory _clientFactory; private readonly UserManager<ApplicationUser> _userManager; private readonly JwtTokenService _jwtTokenService; public YourController(IHttpClientFactory clientFactory, UserManager<ApplicationUser> userManager, JwtTokenService jwtTokenService) { _clientFactory = clientFactory; _userManager = userManager; _jwtTokenService = jwtTokenService; }
2. 修正令牌传递与存储的问题
你之前在注册时创建的HttpClient是局部变量,重定向后会被销毁,令牌自然无法传递到后续请求。正确的做法是将令牌存入Session或Cookie中:
修改注册方法
public async Task<IActionResult> Register(RegisterViewModel registerViewModel) { if (ModelState.IsValid) { var user = new ApplicationUser { UserName = registerViewModel.Username, Email = registerViewModel.Email}; var result = await _userManager.CreateAsync(user, registerViewModel.Password); if (result.Succeeded) { await _signInManager.SignInAsync(user, isPersistent: false); var token = _jwtTokenService.GenerateToken(user); // 将令牌存入Session HttpContext.Session.SetString("JwToken", token); return RedirectToAction("Index", "Home"); } ModelState.AddModelError("", "用户注册失败"); } return View(registerViewModel); }
优化API调用逻辑
public async Task<IActionResult> GetAllSales() { var token = HttpContext.Session.GetString("JwToken"); if (string.IsNullOrWhiteSpace(token)) { // 令牌不存在,跳转到登录页 return RedirectToAction("Login", "Account"); } List<Sale> sales = new List<Sale>(); var client = _clientFactory.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:7015/api/Sales"); // 正确设置Authorization头 request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); if (response.IsSuccessStatusCode) { var apiString = await response.Content.ReadAsStringAsync(); sales = JsonConvert.DeserializeObject<List<Sale>>(apiString); } // MVC控制器返回视图,API控制器则返回Ok(sales) return View(sales); }
3. 解决无法获取已登录用户密码的问题
Identity框架不会存储明文密码,PasswordHash是加密后的字符串,不能用来调用GetToken接口。正确逻辑是:
- 已登录用户无需再调用
GetToken接口,直接在登录/注册时生成令牌并存入Session GetToken接口仅用于外部未登录客户端获取令牌(传入明文账号密码)
修改登录方法(如果有)
public async Task<IActionResult> Login(LoginViewModel model) { if (ModelState.IsValid) { var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false); if (result.Succeeded) { var user = await _userManager.FindByEmailAsync(model.Email); var token = _jwtTokenService.GenerateToken(user); HttpContext.Session.SetString("JwToken", token); return RedirectToAction("Index", "Home"); } ModelState.AddModelError("", "无效的登录尝试"); } return View(model); }
删除冗余的CreateToken方法
直接从Session取令牌即可,无需重复调用GetToken接口。
4. 优化令牌生成逻辑
将令牌生成逻辑抽为独立服务,避免代码重复:
public class JwtTokenService { private readonly IConfiguration _configuration; public JwtTokenService(IConfiguration configuration) { _configuration = configuration; } public string GenerateToken(ApplicationUser user) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_configuration["JWT:TokenSignInKey"]); var claims = new List<Claim> { new Claim(JwtRegisteredClaimNames.Sub, user.Id), new Claim(JwtRegisteredClaimNames.Email, user.Email), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) // 添加唯一标识 }; var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(claims), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } }
在Program.cs注册该服务:
builder.Services.AddScoped<JwtTokenService>();
5. 确保API端JWT认证配置正确
API项目的Program.cs需要配置JWT认证中间件:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(builder.Configuration["JWT:TokenSignInKey"])), ValidateIssuer = false, // 根据你的业务需求调整 ValidateAudience = false // 根据你的业务需求调整 }; }); // 必须添加这两个中间件,顺序不能错 app.UseAuthentication(); app.UseAuthorization();
然后在API控制器上添加[Authorize]特性:
[ApiController] [Route("api/[controller]")] [Authorize] public class SalesController : ControllerBase { // CRUD操作方法 }
内容的提问来源于stack exchange,提问作者Pearl
相关产品推荐
相关产品推荐

