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

Blazor Web App中无法获取AccessToken的问题排查

问题解决:Blazor Web App中Cookie登录后无法获取Access Token

核心问题

通过SignInManager.PasswordSignInAsync完成用户名/密码登录后,在ReturnToMobileApp组件中调用auth.Properties.GetTokenValue("access_token")始终返回null,尽管已添加.AddBearerToken配置使Postman能通过API端点获取Token。

原因分析

PasswordSignInAsync是基于Cookie的认证流程,仅负责创建Cookie会话,默认不会生成Bearer Token,也不会将Token存储到认证会话的Properties中。而.AddBearerToken仅为Identity的API端点(如/login)提供Token生成能力,不会自动关联到Cookie登录会话。

解决方案

需要在登录成功后手动生成Bearer Token,并将Token存储到认证会话的Properties中,这样后续就能在组件中通过GetTokenValue获取。

步骤1:确保服务配置正确

在Program.cs中确认已添加AddBearerToken,并保留Identity的完整配置:

services.AddAuthorizationCore();
services.AddCascadingAuthenticationState();

services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
    options.SignIn.RequireConfirmedAccount = false;
})
.AddEntityFrameworkStores<MyIdentityDbContext>()
.AddSignInManager()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddApiEndpoints()
// 添加Bearer Token生成配置
.AddBearerToken(IdentityConstants.BearerScheme, o =>
{
    o.BearerTokenExpiration = TimeSpan.FromMinutes(5);
});

// 其他Identity配置...
services.ConfigureApplicationCookie(options =>
{
    options.Cookie.Name = "MyApp.Cookie";
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    options.LoginPath = "/Account/Login";
    options.AccessDeniedPath = "/Account/AccessDenied";
    options.SlidingExpiration = true;
});

步骤2:修改登录逻辑,手动生成并存储Token

替换原来的PasswordSignInAsync,改为先验证用户密码,再生成Token并关联到Cookie会话:

[Inject]
public required SignInManager<IdentityUser> SignInManager { get; set; }
[Inject]
public required IBearerTokenGenerator BearerTokenGenerator { get; set; }
[Inject]
public required IdentityRedirectManager RedirectManager { get; set; }
[Inject]
public required ILogger<Login> Logger { get; set; }

// ... 其他代码(如Input模型)

var user = await SignInManager.UserManager.FindByEmailAsync(Input.Email);
if (user != null)
{
    var passwordCheckResult = await SignInManager.CheckPasswordSignInAsync(user, Input.Password, lockoutOnFailure: false);
    if (passwordCheckResult.Succeeded)
    {
        // 生成Bearer Token
        var tokenResult = await BearerTokenGenerator.GenerateAsync(user);
        
        // 创建认证Properties,存储Token和过期时间
        var authProperties = new AuthenticationProperties
        {
            IsPersistent = Input.RememberMe,
            ExpiresUtc = tokenResult.ExpiresUtc
        };
        // 将Access Token和Refresh Token存入Properties
        authProperties.StoreTokens(new[]
        {
            new AuthenticationToken
            {
                Name = "access_token",
                Value = tokenResult.AccessToken
            },
            new AuthenticationToken
            {
                Name = "refresh_token",
                Value = tokenResult.RefreshToken
            }
        });
        
        // 执行登录,将Properties关联到Cookie会话
        await SignInManager.SignInAsync(user, authProperties);
        
        Logger.LogInformation("User logged in successfully.");
        RedirectManager.RedirectTo("Account/ReturnToMobileApp");
    }
    else
    {
        // 处理登录失败逻辑
        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
    }
}
else
{
    ModelState.AddModelError(string.Empty, "No user found with this email.");
}

步骤3:验证组件获取Token

修改后的登录流程会将Token存储到认证会话的Properties中,此时ReturnToMobileApp组件中的auth.Properties.GetTokenValue("access_token")就能正常获取到值:

protected override async Task OnInitializedAsync()
{
    var auth = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme);
    var accessToken = auth.Properties.GetTokenValue("access_token");
    // 后续逻辑...
}

补充说明

Postman能获取Token是因为直接调用了Identity的API端点(如POST /login),这些端点由AddApiEndpoints()和AddBearerToken()提供,会直接返回Token;而Cookie登录流程需要手动关联Token到会话,才能在后续组件中读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:27:05