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

如何通过OAuth令牌实现ASP.NET Core MVC用户登录认证

ASP.NET Core MVC中传递自定义OAuth令牌到认证中间件的问题

问题背景

正在构建的ASP.NET Core MVC Web应用支持两种认证方式:

  • 使用.AddOpenIdConnect()的认证方式已正常运行
  • 另一种需要从Web服务获取OAuth令牌进行认证

MVC控制器代码

// MVC
public async Task<IActionResult> GetToken()
{
    var tokenResponse = await _tokenService.GetToken();

    // 尝试设置请求头,但JwtBearerEvents中未捕获到
    string headerValue = new AuthenticationHeaderValue("Bearer", tokenResponse.AccessToken).ToString();
    Request.Headers.Authorization = headerValue;

    return RedirectToAction("ShowToken", "Account");
}

// 该Action指定使用JwtBearer认证方案
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult ShowToken()
{    
    return View();
}

认证配置代码

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;

    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; 
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.TokenHandlers.Add(new StrictTokenHandler());
    options.TokenValidationParameters = tokenValidationParameters;
    options.SaveToken = true;
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            var p = context.Properties;
            // 此时还未获取到令牌,无法赋值context.Token
            return Task.CompletedTask;
        },
        OnChallenge = context =>
        {
            var p = context.Properties;
            // 这里能拿到令牌,但JwtBearerChallengeContext没有可设置的Token属性
            return Task.CompletedTask;
        },
        OnTokenValidated = context =>
        {
            return Task.CompletedTask;
        },
    };
})
.AddCookie(options =>
{
    options.LoginPath = new PathString("/Account/Login");
})
.AddOpenIdConnect(options =>
{
    options.Authority = issuer;
    // 其余配置省略,此认证方式已正常运行
});

核心问题

  1. 从Web服务获取到OAuth令牌后,如何传递给身份认证中间件?(已尝试设置请求头,但未生效)
  2. 如何配置身份认证中间件来处理这些自定义获取的令牌?

补充:令牌服务返回的信息如下
令牌信息截图


解决方案

问题1:传递令牌到认证中间件

设置Request.Headers无效是因为重定向会创建新请求,原请求的Header不会被携带到跳转后的请求中。推荐两种可靠传递方式:

方式1:临时Cookie存储令牌

在GetToken方法中将令牌存入临时Cookie,有效期设为短时长避免泄露:

public async Task<IActionResult> GetToken()
{
    var tokenResponse = await _tokenService.GetToken();
    // 设置临时Cookie,生产环境启用Secure属性
    Response.Cookies.Append("TempJwtToken", tokenResponse.AccessToken, new CookieOptions
    {
        HttpOnly = true,
        Secure = true,
        Expires = DateTimeOffset.UtcNow.AddMinutes(5),
        Path = "/"
    });

    return RedirectToAction("ShowToken", "Account");
}

方式2:AuthenticationProperties传递

通过跳转时的属性传递令牌,适合短生命周期场景:

public async Task<IActionResult> GetToken()
{
    var tokenResponse = await _tokenService.GetToken();
    var properties = new AuthenticationProperties
    {
        Items = { ["TempToken"] = tokenResponse.AccessToken }
    };

    return RedirectToAction("ShowToken", "Account", properties);
}

问题2:配置中间件处理令牌

在JwtBearer的OnMessageReceived事件中读取存储的令牌,赋值给context.Token让中间件验证:

对应临时Cookie的配置

修改AddJwtBearer的事件逻辑:

.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
    // 保留原有配置
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            // 从临时Cookie读取令牌,验证后可删除
            if (context.Request.Cookies.TryGetValue("TempJwtToken", out var token))
            {
                context.Token = token;
                context.Response.Cookies.Delete("TempJwtToken");
            }
            return Task.CompletedTask;
        },
        // 保留其他事件配置
    };
})

对应AuthenticationProperties的配置

如果用属性传递,在事件中读取:

.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
    // 保留原有配置
    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = context =>
        {
            if (context.Properties.Items.TryGetValue("TempToken", out var token))
            {
                context.Token = token;
            }
            return Task.CompletedTask;
        },
        // 保留其他事件配置
    };
})

额外优化建议

  • 令牌验证通过后,建议调用SignInAsync将身份转换为Cookie认证,后续请求无需重复处理JWT:
    // 可在OnTokenValidated事件或ShowToken Action中添加
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, User);
    
  • 生产环境务必启用HTTPS,确保令牌传输安全。

内容的提问来源于stack exchange,提问作者Mark Good

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:17:05