ASP.NET Web API中Google认证结合JWT授权配置问题求助
问题原因分析
你遇到的错误核心是:JwtBearerHandler仅负责验证JWT令牌,不支持SignInAsync操作——这个方法是用于创建用户会话(比如Cookie认证场景)的。而你把默认认证Scheme全设为了JwtBearer,Google认证完成后框架尝试用该Scheme执行登录操作,自然会报错。
解决方案步骤
1. 修正认证服务配置
调整默认Scheme的分工:让常规API请求用JWT验证,认证挑战(跳转到Google登录)用Google的Scheme。同时配置Google认证的回调路径和用户信息捕获事件。
修改后的服务注册代码:
builder.Services.AddAuthentication(options => { // 常规API请求用JWT验证 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; // 触发登录跳转时用Google的Scheme options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; }) .AddJwtBearer(opt => { opt.SaveToken = true; opt.RequireHttpsMetadata = true; opt.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = !string.IsNullOrEmpty(configuration["JWT:Issuer"]), ValidateAudience = !string.IsNullOrEmpty(configuration["JWT:Audience"]), ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidAudience = configuration["JWT:Audience"], ValidIssuer = configuration["JWT:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Secret"])) }; }) .AddGoogle(googleOptions => { googleOptions.ClientId = configuration["Google:ClientId"]!; googleOptions.ClientSecret = configuration["Google:ClientSecret"]!; // 回调路径要和Google开发者控制台配置的完全一致 googleOptions.CallbackPath = "/api/auth/google-callback"; // 捕获Google返回的用户信息,添加到Claims中 googleOptions.Events.OnCreatingTicket = context => { var email = context.User?.GetValue("email")?.ToString(); var name = context.User?.GetValue("name")?.ToString(); context.Identity?.AddClaim(new Claim(ClaimTypes.Email, email)); context.Identity?.AddClaim(new Claim(ClaimTypes.Name, name)); return Task.CompletedTask; }; });
2. 编写认证回调API端点
创建Auth控制器,处理Google登录的触发和回调,手动生成JWT返回给客户端:
[ApiController] [Route("api/auth")] public class AuthController : ControllerBase { private readonly IConfiguration _configuration; public AuthController(IConfiguration configuration) { _configuration = configuration; } // 触发Google登录跳转 [HttpGet("google-login")] public IActionResult GoogleLogin() { var redirectUrl = Url.Action(nameof(GoogleCallback), "Auth"); var properties = new AuthenticationProperties { RedirectUri = redirectUrl }; return Challenge(properties, GoogleDefaults.AuthenticationScheme); } // Google认证回调,生成JWT返回 [HttpGet("google-callback")] public async Task<IActionResult> GoogleCallback() { var authResult = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme); if (!authResult.Succeeded) { return BadRequest("Google认证失败"); } // 从认证结果中提取用户信息 var userId = authResult.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var email = authResult.Principal.FindFirstValue(ClaimTypes.Email); var name = authResult.Principal.FindFirstValue(ClaimTypes.Name); // 生成JWT令牌 var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]!); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId), new Claim(ClaimTypes.Email, email), new Claim(ClaimTypes.Name, name) }), Expires = DateTime.UtcNow.AddHours(2), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature), Issuer = _configuration["JWT:Issuer"], Audience = _configuration["JWT:Audience"] }; var token = tokenHandler.CreateToken(tokenDescriptor); var jwtToken = tokenHandler.WriteToken(token); return Ok(new { Token = jwtToken }); } }
3. 关键注意事项
- 回调路径必须和Google开发者控制台中配置的授权重定向URI完全匹配(本地测试用
https://localhost:xxxx/api/auth/google-callback,线上替换为你的域名)。 - 确保appsettings.json中JWT的
Issuer、Audience、Secret配置项正确。 - 客户端拿到JWT后,后续请求需在
Authorization头中携带Bearer {token}来访问需要认证的API接口。
内容的提问来源于stack exchange,提问作者xarielah
相关产品推荐
相关产品推荐

