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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:30:51