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

.NET8 MVC中SignInManager.PasswordSignInAsync成功后用户未登录

问题描述

使用.NET 8 MVC开发时遇到以下问题:调用SignInManager.PasswordSignInAsync方法返回登录成功,但用户实际并未登录:

  • 登录后本该显示导航栏,却被重定向到登录页
  • 访问带有[Authorize]特性的AdminController时也会被重定向

调试发现:

  • _Layout.cshtml中的@if(SignInManager.IsSignedIn(User))判断始终为false
  • 在HomeController的Login方法中,通过CreateUserPrincipalAsync生成的用户主体验证IsSignedIn却为true

相关代码如下:

Program.cs

builder.Services.AddDefaultIdentity<User>()
    .AddRoles<IdentityRole<int>>()
    .AddEntityFrameworkStores<MyDBContext>();

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(opts => {
        opts.LoginPath = "/Home/Login";
        opts.LogoutPath = "/Home/Login";
        opts.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        opts.AccessDeniedPath = "/Home/Unauthorized";
        opts.SlidingExpiration = true;
    });

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

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

app.Run();

HomeController.cs

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly SignInManager<User> _signInManager;

    public HomeController(ILogger<HomeController> logger, SignInManager<User> signInManager)
    {
        _logger = logger;
        _signInManager = signInManager;
    }

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

        _logger.LogInformation("Trying to sign in user");
        var result = await _signInManager.PasswordSignInAsync(loginCreds.Email, loginCreds.Password, false, false);
        if(!result.Succeeded)
        {
            _logger.LogInformation("Failed attempt");

            ModelState.AddModelError(string.Empty, "Hmm something went wrong!");
            return View(loginCreds);
        }

        // 调试代码
        var user = await _userManager.FindByEmailAsync(loginCreds.Email);
        var userPrincipals = await _signInManager.CreateUserPrincipalAsync(user);
        // Boolean comes out true
        bool signdIn = _signInManager.IsSignedIn(userPrincipals);
        _logger.LogInformation("Succeeded " + signdIn);

        _logger.LogInformation("Succeeded");
        return RedirectToAction("NewClient", "Admin");
    }

    public IActionResult Login()
    {
        return View();
    }

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

_Layout.cshtml

@using Microsoft.AspNetCore.Identity
@inject SignInManager<User> SignInManager

    <body>
        // Why does this come back false when user is signed in
        @if(SignInManager.IsSignedIn(User))
        {
        <header>
            <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
                <div class="container-fluid">
                    <a class="navbar-brand" asp-area="" asp-controller="Admin" asp-action="Dashboard">SuperAnchor</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                            aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                        <ul class="navbar-nav flex-grow-1">
                            <li class="nav-item">
                                <a class="nav-link text-dark" asp-area="" asp-controller="Admin" asp-action="Dashboard">Home</a>
                            </li>
                            @* <li class="nav-item">
                                <a class="nav-link text-dark" asp-area="" asp-controller="Admin" asp-action="TestPage">Test Page</a>
                                @Html.ActionLink("Test Link Page", "TestPage", "Admin", null, new { @class="nav-link text-dark" })
                            </li> *@
                            <li class="nav-item">
                                <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                            </li>
                            @if(User.IsInRole("Admin"))
                            {
                                <li class="nav-item">
                                    <a class="nav-link text-dark" asp-area="" asp-controller="Admin" asp-action="NewClient">Add new Client</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link text-dark" asp-area="" asp-controller="Admin" asp-action="AddProduct">Add new Product</a>
                                </li>
                            }
                        </ul>
                    </div>
                    @await Html.PartialAsync("_LoginPartial")
                </div>
            </nav>
        </header>
        }

        <div class="container">
            <main role="main" class="pb-3">
                @* @await Html. *@
                @RenderBody()
            </main>
        </div>
    </body>
</html>

AdminController.cs

[Authorize]
public class AdminController : Controller
{
    private readonly ILogger<AdminController> _logger;
    private readonly UserManager<User> _userManager;
    private readonly RoleManager<IdentityRole<int>> _roleManager;

    public AdminController(ILogger<AdminController> logger, UserManager<User> userManager, RoleManager<IdentityRole<int>> roleManager)
    {
        _logger = logger;
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public IActionResult NewClient()
    {
        return View();
    }
}
问题原因及解决方法

核心问题是重复配置了认证系统:AddDefaultIdentity已经自动为Identity框架配置了Cookie认证,包括默认的Cookie名称、认证Scheme等。手动调用AddAuthentication().AddCookie()会覆盖这些默认配置,导致SignInManager生成的认证Cookie无法被后续请求的认证中间件识别,从而出现"登录成功但实际未登录"的现象。

具体修复步骤:

  1. 移除重复的认证配置:删除Program.cs中以下代码段:
    builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(opts => {
            opts.LoginPath = "/Home/Login";
            opts.LogoutPath = "/Home/Login";
            opts.ExpireTimeSpan = TimeSpan.FromMinutes(30);
            opts.AccessDeniedPath = "/Home/Unauthorized";
            opts.SlidingExpiration = true;
        });
    
  2. 自定义Identity Cookie配置(可选):如果需要修改Cookie的参数,直接通过AddDefaultIdentity的扩展方法配置,不要单独添加Cookie认证:
    builder.Services.AddDefaultIdentity<User>()
        .AddRoles<IdentityRole<int>>()
        .AddEntityFrameworkStores<MyDBContext>()
        .AddCookie(options =>
        {
            options.LoginPath = "/Home/Login";
            options.LogoutPath = "/Home/Login";
            options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
            options.AccessDeniedPath = "/Home/Unauthorized";
            options.SlidingExpiration = true;
        });
    
  3. 补充HomeController的依赖注入:Login方法中使用了_userManager但构造函数未注入,需要补充:
    private readonly UserManager<User> _userManager;
    
    public HomeController(ILogger<HomeController> logger, SignInManager<User> signInManager, UserManager<User> userManager)
    {
        _logger = logger;
        _signInManager = signInManager;
        _userManager = userManager;
    }
    
  4. 验证中间件顺序:确保UseAuthentication()和UseAuthorization()在UseRouting()之后,当前代码中的顺序是正确的,无需调整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 12:07:07