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

ASP.NET Core WebApi中如何禁用SignInManager的Cookie仅用JWTBearer

解决方案:禁用SignInManager的Cookie并仅使用JWT Bearer认证

没问题,我来帮你搞定这个问题——在ASP.NET Core WebApi中结合Identity和JWT Bearer认证,同时避免SignInManager生成Cookie,核心是调整Identity的配置并替换默认的登录逻辑,具体步骤如下:

1. 调整Identity配置,从根源禁用默认Cookie认证

默认情况下,AddIdentity会自动注册Cookie认证方案,这就是SignInManager生成Cookie的原因。我们可以改用更轻量的AddIdentityCore来配置Identity,它不会自动绑定Cookie认证,完美适配WebApi场景:

services.AddIdentityCore<ApplicationUser>(options =>
{
    // 这里配置你的Identity规则,比如密码复杂度、用户名验证等
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    // ...其他自定义配置
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager() // 保留SignInManager,但它不会默认关联Cookie
.AddDefaultTokenProviders();

如果你已经在使用AddIdentity,也可以通过修改Cookie配置来禁用它:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    // 你的Identity配置
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();

// 禁用Cookie生成或调整其行为
services.ConfigureApplicationCookie(options =>
{
    // 对于WebApi,我们不需要重定向到登录页,直接返回401
    options.Events.OnRedirectToLogin = context =>
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        return Task.CompletedTask;
    };
    // 或者直接设置空Cookie名称,阻止Cookie生成
    options.Cookie.Name = string.Empty;
});

2. 替换SignInManager.PasswordSignInAsync为手动验证+JWT生成

PasswordSignInAsync的设计初衷就是为Cookie认证创建会话,所以即使禁用了Cookie,这个方法可能仍会尝试生成无效的Cookie。更好的方式是直接用UserManager验证密码,然后手动生成JWT令牌返回给客户端:

先确保JWT Bearer认证已正确配置

在ConfigureServices中添加JWT Bearer的配置:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = Configuration["Jwt:Issuer"],
        ValidAudience = Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
    };
});

在登录接口中实现手动验证和JWT生成

不再调用SignInManager.PasswordSignInAsync,而是用UserManager.CheckPasswordAsync验证用户凭证,然后生成JWT返回:

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IConfiguration _configuration;

    public AuthController(UserManager<ApplicationUser> userManager, IConfiguration configuration)
    {
        _userManager = userManager;
        _configuration = configuration;
    }

    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginModel model)
    {
        var user = await _userManager.FindByNameAsync(model.Username);
        if (user != null && await _userManager.CheckPasswordAsync(user, model.Password))
        {
            // 构建JWT声明
            var authClaims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, user.UserName),
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                // 按需添加用户角色等其他声明
            };

            var userRoles = await _userManager.GetRolesAsync(user);
            foreach (var role in userRoles)
            {
                authClaims.Add(new Claim(ClaimTypes.Role, role));
            }

            // 生成JWT令牌
            var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
            var token = new JwtSecurityToken(
                issuer: _configuration["Jwt:Issuer"],
                audience: _configuration["Jwt:Audience"],
                expires: DateTime.Now.AddHours(3),
                claims: authClaims,
                signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
            );

            return Ok(new
            {
                token = new JwtSecurityTokenHandler().WriteToken(token),
                expiration = token.ValidTo
            });
        }
        return Unauthorized("用户名或密码错误");
    }
}

这样处理后,登录接口只会返回JWT令牌,不会生成任何Cookie,完全符合WebApi的无状态认证需求。

3. 确保中间件顺序正确

在Configure方法中,一定要保证UseAuthentication在UseAuthorization之前,这样请求会先完成认证再进行授权检查:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...其他中间件(比如异常处理、静态文件等)

    app.UseRouting();

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

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

完成以上配置后,你的WebApi就只会通过请求头中的Authorization: Bearer {你的JWT令牌}来验证身份,再也不会生成Cookie了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:45:09