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

如何在ASP.NET Core 6 Web API中将Google外部登录写入Identity表

ASP.NET Core Identity 提供了完整的内置能力实现这个需求,不需要手动编写SQL操作Users、UserLogins、UserClaims等表。网上MVC场景的教程核心逻辑完全适用于WebAPI,唯一区别是WebAPI不需要处理视图渲染、浏览器重定向逻辑,所有接口直接返回JSON结果即可。

具体实现步骤

1. 安装依赖并配置服务

首先确保项目引入以下NuGet包:

  • Microsoft.AspNetCore.Authentication.JwtBearer
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore
  • Microsoft.AspNetCore.Authentication.Google

在Program.cs中注册服务,注意和MVC场景的核心差异是不要将Cookie认证作为默认方案,避免未认证时触发302跳转:

// 注册Identity服务,和你原有本地账号登录的配置保持一致即可
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

// 配置JWT为API默认认证方案
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(/* 保留你原有校验系统自有JWT的配置 */)
.AddGoogle(googleOptions =>
{
    googleOptions.ClientId = builder.Configuration["Authentication:Google:ClientId"];
    googleOptions.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
    // 关键配置:指定外部登录结果的临时存储方案,禁止自动触发浏览器跳转
    googleOptions.SignInScheme = IdentityConstants.ExternalScheme;
});

2. 编写Google登录接口

前端通过Google SDK拿到id_token后,直接POST给后端接口,接口内完全使用Identity内置方法完成逻辑,不需要手动操作数据库:

[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly SignInManager<IdentityUser> _signInManager;

    public AuthController(UserManager<IdentityUser> userManager, SignInManager<IdentityUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    [HttpPost("google-login")]
    public async Task<IActionResult> GoogleLogin([FromBody] GoogleLoginRequest request)
    {
        // 内置方法自动校验Google JWT合法性,解析出Google返回的用户身份信息
        var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync(
            loginProvider: "Google",
            providerKey: null,
            authenticationToken: request.GoogleIdToken);

        if (externalLoginInfo == null)
        {
            return BadRequest("Google令牌校验失败,请重新登录");
        }

        // 查询系统内是否已存在绑定该Google账号的用户
        var existingUser = await _userManager.FindByLoginAsync(externalLoginInfo.LoginProvider, externalLoginInfo.ProviderKey);
        bool isNewUser = false;

        if (existingUser == null)
        {
            isNewUser = true;
            // 从Google返回的身份信息中提取邮箱作为新用户账号
            var email = externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email);
            var newUser = new IdentityUser
            {
                UserName = email,
                Email = email,
                EmailConfirmed = true // Google已完成邮箱验证,直接标记为已确认
            };

            // 内置方法创建用户,自动写入Users表
            var createUserResult = await _userManager.CreateAsync(newUser);
            if (!createUserResult.Succeeded)
            {
                return BadRequest(createUserResult.Errors);
            }

            // 内置方法关联Google登录信息,自动写入UserLogins表
            var addLoginResult = await _userManager.AddLoginAsync(newUser, externalLoginInfo);
            if (!addLoginResult.Succeeded)
            {
                return BadRequest(addLoginResult.Errors);
            }

            // 如需存储Google返回的姓名、头像等信息,用内置方法写入UserClaims表
            var requiredClaims = externalLoginInfo.Principal.Claims.Where(c => 
                c.Type is ClaimTypes.Name or ClaimTypes.GivenName or "picture"
            );
            await _userManager.AddClaimsAsync(newUser, requiredClaims);

            existingUser = newUser;
        }

        // 执行登录逻辑,生成系统自有JWT返回给前端
        await _signInManager.SignInAsync(existingUser, isPersistent: false);
        var appToken = GenerateYourOwnJwtToken(existingUser); // 替换为你项目原有的JWT生成逻辑

        return Ok(new
        {
            AccessToken = appToken,
            IsNewUser = isNewUser,
            UserName = existingUser.UserName
        });
    }
}

public class GoogleLoginRequest
{
    public string GoogleIdToken { get; set; }
}
注意事项
  • 所有用到的GetExternalLoginInfoAsync、CreateAsync、AddLoginAsync、AddClaimsAsync都是Identity的内置方法,会自动维护各张Identity表的关联关系和字段约束,和MVC场景调用的方法完全一致。
  • 前端集成Google SDK时,必须申请openid、email、profile权限,否则后端拿不到邮箱、姓名等必要的用户信息。
  • 如果需要扩展用户字段(比如增加头像、用户等级字段),只要将代码中的IdentityUser替换为你自定义的继承自IdentityUser的用户类即可,其他逻辑不需要调整。
  • 不要去掉googleOptions.SignInScheme = IdentityConstants.ExternalScheme配置,否则接口在校验失败时会返回302重定向响应,不符合WebAPI的返回规范。

内容的提问来源于stack exchange,提问作者CSharp-n

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 00:57:19