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

Blazor Server项目中Google认证回调User为空的调试求助

问题

在Blazor Server Web应用中实现Google认证,应用使用Identity框架的UserManager和SignInManager,但采用自定义Razor Pages。目标是获取用户选择的谷歌账户信息并在数据库中创建对应用户,但回调方法中User对象始终为空,无法通过if (GoogleUser.IsAuthenticated)判断。以下是相关代码:

Program.cs代码

var builder = WebApplication.CreateBuilder(args);

// 添加数据库和数据库认证配置
var connectionString = builder.Configuration.GetConnectionString("StatTrade");
builder.Services.AddDbContext<StatTradeDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
    options.Password.RequireDigit = false;
    options.Password.RequiredLength = 5;
    options.Password.RequireLowercase = false;
    options.Password.RequireUppercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.SignIn.RequireConfirmedEmail = false;
})
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<StatTradeDbContext>();

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme;
})
    .AddCookie()
    .AddGoogle(GoogleDefaults.AuthenticationScheme, opt =>
    {
        opt.ClientId = builder.Configuration["Google:Id"];
        opt.ClientSecret = builder.Configuration["Google:Secret"];
        opt.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");

    });

builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<HttpContextAccessor>();
builder.Services.AddHttpClient();
builder.Services.AddScoped<HttpClient>();

// 添加服务到容器
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

// 添加fontawesome依赖
builder.Services
    .AddBlazorise()
    .AddBootstrap5Providers()
    .AddFontAwesomeIcons();

AddBlazorise(builder.Services);

var app = builder.Build();

// 配置HTTP请求管道
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();

// 添加微软标准认证系统
app.UseAuthentication();
app.UseAuthorization();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.MapRazorPages();

app.Run();

void AddBlazorise(IServiceCollection services)
{
    services
        .AddBlazorise();
    services
        .AddBootstrap5Providers()
        .AddFontAwesomeIcons();
}

Razor页面代码(LoginModel.cs)

namespace BlazorGmail.Pages.Identity
{
    [AllowAnonymous]
    public class LoginModel : PageModel
    {
       
        public IActionResult OnGetAsync(string returnUrl = null)
        {
            // 请求重定向到外部登录提供者
            var authenticationProperties = new AuthenticationProperties
            {
                RedirectUri = Url.Page("./GoogleLogin",
                pageHandler: "Callback",
                values: new { returnUrl }),

            };
            return new ChallengeResult(GoogleDefaults.AuthenticationScheme, authenticationProperties);
        }
        public async Task<IActionResult> OnGetCallbackAsync(
            string returnUrl = null, string remoteError = null)
        {
            // 从外部登录提供者获取用户信息
            var GoogleUser = this.User.Identities.FirstOrDefault();
            if (GoogleUser.IsAuthenticated)
            {
                var authProperties = new AuthenticationProperties
                {
                    IsPersistent = true,
                    RedirectUri = this.Request.Host.Value
                };
                await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(GoogleUser),
                authProperties);
            }
            return LocalRedirect("/");
        }
    }
}

调试方向建议

  • 修正认证Scheme冲突:AddIdentity已经默认注册了基于IdentityConstants.ApplicationScheme的Cookie认证,手动添加的AddCookie()会创建另一个Cookie Scheme,导致认证上下文混乱。可以去掉手动的.AddCookie(),或者将认证配置的DefaultScheme改为IdentityConstants.ApplicationScheme,保持Scheme统一。

  • 调整回调地址的正确性:当前OnGetAsync中设置的RedirectUri指向./GoogleLogin,但你的PageModel是LoginModel(对应Login.cshtml),回调方法属于当前页面,应该改为:

    RedirectUri = Url.Page("./Login", pageHandler: "Callback", values: new { returnUrl })
    

    确保回调请求能正确路由到当前页面的OnGetCallbackAsync方法。

  • 改用SignInManager获取外部登录信息:回调方法中不能直接通过this.User获取谷歌用户信息,此时还未完成本地认证。应该注入SignInManager<IdentityUser>,并调用GetExternalLoginInfoAsync()来获取谷歌返回的用户数据:

    private readonly SignInManager<IdentityUser> _signInManager;
    public LoginModel(SignInManager<IdentityUser> signInManager)
    {
        _signInManager = signInManager;
    }
    
    public async Task<IActionResult> OnGetCallbackAsync(string returnUrl = null, string remoteError = null)
    {
        var loginInfo = await _signInManager.GetExternalLoginInfoAsync();
        if (loginInfo == null)
        {
            // 处理获取失败的情况
            return LocalRedirect("/");
        }
        // 从loginInfo中获取谷歌用户的Email、Name等信息
        var email = loginInfo.Principal.FindFirstValue(ClaimTypes.Email);
        // 后续创建用户或关联现有用户逻辑
    }
    
  • 完善Google Claim映射:当前只映射了头像信息,需要添加邮箱、姓名等Claim的映射,确保能获取到必要的用户数据:

    .AddGoogle(GoogleDefaults.AuthenticationScheme, opt =>
    {
        opt.ClientId = builder.Configuration["Google:Id"];
        opt.ClientSecret = builder.Configuration["Google:Secret"];
        opt.ClaimActions.MapJsonKey("urn:google:picture", "picture", "url");
        opt.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");
        opt.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
    });
    
  • 启用认证日志排查:在appsettings.json中添加认证相关的调试日志,查看认证流程中的错误或警告:

    "Logging": {
        "LogLevel": {
            "Microsoft.AspNetCore.Authentication": "Debug"
        }
    }
    
  • 检查中间件顺序:确保UseAuthentication()和UseAuthorization()在UseRouting()之后,MapBlazorHub()、MapRazorPages()之前,当前代码顺序正确,但如果后续调整配置需保持这个顺序。

内容的提问来源于stack exchange,提问作者Miky-Bet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 13:05:23