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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 20:31:13