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

如何通过外部JWT认证保护ASP.NET Core 6 MVC应用的视图?

解决方案步骤

1. 处理登录逻辑

先创建登录视图模型,接收表单输入:

public class LoginViewModel
{
    [Required]
    public string Username { get; set; }
    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
}

在AccountController中实现登录动作,调用外部API获取JWT并完成用户认证:

public class AccountController : Controller
{
    private readonly HttpClient _httpClient;

    public AccountController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    [HttpGet]
    public IActionResult Login() => View();

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (!ModelState.IsValid)
            return View(model);

        // 调用外部登录API提交凭证
        var loginPayload = new { Username = model.Username, Password = model.Password };
        var response = await _httpClient.PostAsJsonAsync("https://external-api-domain/login", loginPayload);

        if (!response.IsSuccessStatusCode)
        {
            ModelState.AddModelError(string.Empty, "登录失败,请检查用户名或密码");
            return View(model);
        }

        var jwtToken = await response.Content.ReadAsStringAsync();
        // 解析JWT获取用户声明,用于Cookie认证
        var jwtHandler = new JwtSecurityTokenHandler();
        var jwtTokenObj = jwtHandler.ReadJwtToken(jwtToken);

        var claims = jwtTokenObj.Claims.ToList();
        // 将原始JWT存入声明,方便后续调用数据API
        claims.Add(new Claim("JwtToken", jwtToken));

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var authProps = new AuthenticationProperties
        {
            IsPersistent = true,
            ExpiresUtc = jwtTokenObj.ValidTo
        };

        // 生成认证Cookie,完成用户登录
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 
                                      new ClaimsPrincipal(identity), authProps);

        return RedirectToAction("Index", "Home");
    }

    [HttpPost]
    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return RedirectToAction("Login");
    }
}

2. 配置认证与服务

在Program.cs中配置Cookie认证和HttpClient服务:

var builder = WebApplication.CreateBuilder(args);

// 注册HttpClient,用于调用外部API
builder.Services.AddHttpClient();

// 添加MVC服务
builder.Services.AddControllersWithViews();

// 配置Cookie认证
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login"; // 未认证用户跳转路径
        options.LogoutPath = "/Account/Logout";
        options.ExpireTimeSpan = TimeSpan.FromHours(1);
        options.SlidingExpiration = true;
        options.Cookie.HttpOnly = true; // 禁止前端JS读取,防XSS
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 生产环境强制HTTPS
    });

var app = builder.Build();

// 中间件顺序不可乱
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

// 先执行认证,再执行授权
app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

3. 页面授权与数据API调用

用[Authorize]标记需要认证的控制器/动作,在业务逻辑中取出JWT调用外部数据API:

[Authorize]
public class HomeController : Controller
{
    private readonly HttpClient _httpClient;

    public HomeController(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<IActionResult> Index()
    {
        // 从用户声明中获取存储的JWT
        var jwtToken = User.FindFirstValue("JwtToken");
        if (string.IsNullOrEmpty(jwtToken))
            return RedirectToAction("Login", "Account");

        // 给请求添加Bearer令牌,调用外部数据API
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken);
        var data = await _httpClient.GetFromJsonAsync<YourDataModel>("https://external-api-domain/data");

        return View(data);
    }
}

4. 登录视图(Login.cshtml)

创建基础登录表单:

@model LoginViewModel

<h1>用户登录</h1>

<div asp-validation-summary="ModelOnly" class="text-danger"></div>

<form method="post">
    <div class="form-group">
        <label asp-for="Username"></label>
        <input asp-for="Username" class="form-control" />
        <span asp-validation-for="Username" class="text-danger"></span>
    </div>
    <div class="form-group">
        <label asp-for="Password"></label>
        <input asp-for="Password" class="form-control" />
        <span asp-validation-for="Password" class="text-danger"></span>
    </div>
    <button type="submit" class="btn btn-primary">登录</button>
</form>

关键注意事项

  • JWT存储安全:将JWT存入HttpOnly Cookie或用户声明,避免前端直接操作,降低XSS风险。
  • 令牌过期处理:实际项目中需捕获令牌过期的API返回,自动跳转到登录页重新获取令牌。
  • 生产环境配置:确保外部API和自身站点都使用HTTPS,防止令牌在传输过程中被窃取。

内容的提问来源于stack exchange,提问作者A Gilani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:03:44