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

基于WsFederation实现MVC与WebAPI控制器的Cookie+Bearer Token双重认证

实现WsFederation同时生成Cookie和Bearer Token的方案

完全可以实现你的需求,核心思路是在WsFederation完成用户认证后,额外生成JWT格式的Bearer Token,并将其传递给前端SPA。下面是具体的分步实现:

1. 配置JWT认证参数

首先在appsettings.json里添加JWT相关配置:

"JwtSettings": {
  "SecretKey": "your-strong-secret-key-here-make-it-long-and-random",
  "Issuer": "your-app-domain",
  "Audience": "your-api-audience",
  "ExpiresInMinutes": 60
}

然后在Program.cs(或.NET Core 3.1及更早版本的Startup.cs)里注册并配置认证服务:

// 读取JWT配置
var jwtSettings = builder.Configuration.GetSection("JwtSettings").Get<JwtSettings>();
builder.Services.AddSingleton(jwtSettings);

// 配置认证:同时启用WsFederation和JWT
builder.Services.AddAuthentication()
    .AddWsFederation(options => {
        // 保留你原有的WsFederation配置
        options.MetadataAddress = "your-idp-metadata-url";
        options.Wtrealm = "your-app-realm";
        
        // 关键:添加认证成功后的事件处理
        options.Events = new WsFederationEvents
        {
            OnSecurityTokenValidated = async context =>
            {
                // 基于已验证的用户身份生成JWT Token
                var jwtHandler = new JwtSecurityTokenHandler();
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey));
                var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Subject = context.Principal.Identity as ClaimsIdentity,
                    Expires = DateTime.UtcNow.AddMinutes(jwtSettings.ExpiresInMinutes),
                    Issuer = jwtSettings.Issuer,
                    Audience = jwtSettings.Audience,
                    SigningCredentials = credentials
                };

                var token = jwtHandler.CreateToken(tokenDescriptor);
                var tokenString = jwtHandler.WriteToken(token);

                // 将Token存入用户Claims,方便后续MVC控制器获取
                context.Principal.Identities.First().AddClaim(new Claim("BearerToken", tokenString));
            }
        };
    })
    .AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = jwtSettings.Issuer,
            ValidAudience = jwtSettings.Audience,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
        };
    });

需要创建对应配置类绑定JWT参数:

public class JwtSettings
{
    public string SecretKey { get; set; }
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public int ExpiresInMinutes { get; set; }
}

2. 在MVC控制器中传递Token到SPA

当用户点击主页的应用链接时,对应的MVC控制器可以从当前用户Claims中取出Token,再传递给SPA视图:

public class SpaLaunchController : Controller
{
    public IActionResult App1()
    {
        // 从用户Claims中获取Bearer Token
        var bearerToken = User.FindFirst("BearerToken")?.Value;
        
        // 通过ViewBag将Token传递给视图
        ViewBag.BearerToken = bearerToken;
        
        // 返回SPA的入口视图
        return View();
    }
}

在对应的视图(比如App1.cshtml)中,把Token注入到SPA初始化逻辑里:

<script>
    // 将Token暴露给SPA应用
    window.appConfig = {
        bearerToken: '@Html.Raw(ViewBag.BearerToken)'
    };
    
    // 加载你的SPA入口脚本(React/Vue等)
    // ...
</script>

3. WebAPI端验证Bearer Token

确保WebAPI控制器启用JWT认证:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    [HttpGet]
    public IActionResult GetUserInfo()
    {
        // 获取当前用户的ClaimsIdentity
        var identity = User.Identity as ClaimsIdentity;
        return Ok(new { UserName = identity.Name, Claims = identity.Claims.Select(c => new { c.Type, c.Value }) });
    }
}

关键注意事项

  • Token安全:务必使用HTTPS传输Token,避免明文泄露;同时设置合理的过期时间,必要时实现Token刷新机制。
  • Cookie大小限制:如果用户Claims较多,加上Token可能超出Cookie上限,这种情况可以考虑将Token存储在Redis等服务器端,传递一个引用ID给前端,再通过ID换取Token(会增加复杂度)。
  • 事件时机:OnSecurityTokenValidated是生成Token的最佳时机,此时用户身份已完成验证,确保Token基于合法身份生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:52:28