ASP.NET Core 7.0 Web API对接Google的OIDC流程问题
解决Google OIDC回调中code参数为null的问题及Web API认证实现方案
问题根源分析
你当前的代码存在两个核心问题:
- 回调方法的参数绑定错误:Google的OIDC回调会将
code放在URL查询参数中,但你用object code = null的方式无法正确绑定到该参数。 - 默认认证配置不匹配纯API场景:你将Google认证设为默认认证方案,但纯API服务的核心认证应该是JWT Bearer,且默认的Google认证中间件已经自动处理了
code到令牌的交换流程,无需手动提取code。
一、修正认证服务配置
调整认证方案优先级,添加JWT Bearer支持(供其他微服务验证令牌),并配置Google认证保存令牌信息:
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; // 注册服务 services.AddAuthentication(options => { // API默认用JWT Bearer做认证 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; // 发起认证挑战时用Google方案 options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; }) // 添加JWT Bearer认证(供其他微服务验证令牌) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "你的身份微服务域名", // 示例:https://identity.yourdomain.com ValidAudience = "你的API资源标识", // 示例:api://your-service-api IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("至少32位长度的安全签名密钥")) }; }) .AddGoogle(options => { options.ClientId = "你的Google Client ID"; options.ClientSecret = "你的Google Client Secret"; // 回调路径必须与Google开发者控制台配置的完全一致 options.CallbackPath = "/api/v1/Identity/callback"; // 开启令牌保存,用于后续获取Google的ID Token和Access Token options.SaveTokens = true; // 声明需要获取的用户信息范围 options.Scope.Add("openid"); options.Scope.Add("email"); options.Scope.Add("profile"); }); services.AddAuthorization(); // 注册自定义令牌生成服务 services.AddScoped<ITokenService, TokenService>();
二、修正控制器代码
利用认证中间件的自动处理,从HttpContext中直接获取认证结果和令牌,无需手动处理code:
using System.Security.Claims; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; [Route("api/v1/[controller]/[action]")] [ApiController] public class IdentityController : ControllerBase { private readonly ITokenService _tokenService; public IdentityController(ITokenService tokenService) { _tokenService = tokenService; } [AllowAnonymous] [HttpGet] public IActionResult SignIn() { var authProps = new AuthenticationProperties { IsPersistent = false, RedirectUri = Url.Action("Callback", "Identity") }; // 发起Google认证挑战 return Challenge(GoogleDefaults.AuthenticationScheme, authProps); } [AllowAnonymous] [HttpGet] public async Task<IActionResult> Callback() { // 获取Google认证结果 var authResult = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme); if (!authResult.Succeeded) { return BadRequest("Google认证失败"); } // 从认证结果中提取Google颁发的令牌 var googleIdToken = authResult.Properties.GetTokenValue("id_token"); var googleAccessToken = authResult.Properties.GetTokenValue("access_token"); // 提取用户基本信息 var userId = authResult.Principal.FindFirstValue(ClaimTypes.NameIdentifier); var email = authResult.Principal.FindFirstValue(ClaimTypes.Email); var userName = authResult.Principal.FindFirstValue(ClaimTypes.Name); // 生成供自身微服务使用的JWT令牌 var apiJwt = _tokenService.GenerateJwtToken(userId, email, userName); // 返回令牌信息给客户端 return Ok(new { AccessToken = apiJwt, GoogleIdToken = googleIdToken, ExpiresIn = 3600 // 令牌过期时间(秒) }); } [Authorize] [HttpGet] public async Task<IActionResult> Logout() { // 清除Google认证会话和本地认证状态 await HttpContext.SignOutAsync(GoogleDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(JwtBearerDefaults.AuthenticationScheme); return Ok("登出成功"); } }
三、实现自定义JWT令牌生成服务
用于生成供内部微服务使用的JWT令牌:
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; public interface ITokenService { string GenerateJwtToken(string userId, string email, string userName); } public class TokenService : ITokenService { private readonly IConfiguration _config; public TokenService(IConfiguration config) { _config = config; } public string GenerateJwtToken(string userId, string email, string userName) { var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, userId), new Claim(ClaimTypes.Email, email), new Claim(ClaimTypes.Name, userName) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _config["Jwt:Issuer"], audience: _config["Jwt:Audience"], claims: claims, expires: DateTime.UtcNow.AddHours(1), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } }
四、关键注意事项
- Google控制台配置:确保
/api/v1/Identity/callback已添加到Google Cloud Console中OAuth 2.0客户端的「授权重定向URI」列表,否则会回调失败。 - 中间件顺序:必须保证
app.UseAuthentication()在app.UseAuthorization()之前执行,否则认证逻辑不会生效。 - 密钥安全:JWT签名密钥必须使用环境变量存储,禁止硬编码到代码中。
内容的提问来源于stack exchange,提问作者Dr. Strangelove
相关产品推荐
相关产品推荐

