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

Asp.Net5集成Google OAuth2时重定向不匹配问题求助

Asp.Net5集成Google OAuth2的重定向问题

我在Asp.Net5中集成Google OAuth2时遇到了重定向不匹配问题。目前Google控制台中配置的回调地址为https://localhost:4200/signin-google,但我的应用并未设置该路由,因此触发Error 400: redirect_uri_mismatch错误。

若将Google控制台和GoogleOptions的CallbackPath均设置为https://localhost:4200/api/google/response,挑战重定向可成功完成,且能获取到包含谷歌用户信息(姓名、邮箱等)的Cookie,但/api/google/response接口始终未触发(控制台无输出)。

我发现许多教程仅在Google控制台配置https://localhost:4200/signin-google,既不设置CallbackPath也不配置对应路由却能正常运行,这让我十分困惑。请问:

  1. 我是否应回到两端都配置https://localhost:4200/api/google/response的方案,排查接口未触发的原因?
  2. 是否需要在应用中添加/signin-google路由?
  3. 为何多数教程无需配置CallbackPath和路由就能正常工作,而我的情况却不行?

相关代码

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  // configurations
  services.Configure<EnvironmentVariables>(Configuration.GetSection(EnvironmentVariables.EnvironmentVariable));
  services.Configure<RabbitMQSettingsOptions>(Configuration.
   GetSection(RabbitMQSettingsOptions.RabbitMQSettings));

  services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
 .AddCookie(options =>
  {
    this.SetUpCookieAuthentication(options);
  });

  services.AddAuthentication().AddGoogle(options =>
  {
    this.SetUpGoogleAuthentication(options);
  });

  services.AddCors(options =>
  {
    this.SetUpCorsPolicy(options);
  });

 ...
}
private void SetUpGoogleAuthentication(GoogleOptions options)
{
 ...
  // set GoogleOptions
  //options.CallbackPath = new PathString(path);
  options.ClientSecret = googleAuthentication.ClientSecret;
  options.ClientId = googleAuthentication.ClientId;
  
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }
  //app.UseHttpsRedirection();

  app.UseRouting();

  app.UseCors("CorsPolicy");
  // app.UseSession();
  app.UseAuthentication();
  app.UseAuthorization();
  app.UseCookiePolicy();

  app.UseEndpoints(endpoints =>
  {
    endpoints.MapControllers();
  });
}

GoogleController.cs

using AutoMapper.Internal;
using Domain.DDtos.Users;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using ServiceLayer.Dtos.Users;
using ServiceLayer.Interfaces;
using ServiceLayer.Services;
using ServiceLayer.Types;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Eshop.Controllers
{
  [Route("api/google")]
  [ApiController]
  public class GoogleController : ControllerBase
  {
    private IOptions<EnvironmentVariables> _envOptions;
    private readonly IEnvironmentVariableService _envService;
    private readonly IUserService _userService;

    public GoogleController(IOptions<EnvironmentVariables> envOptions,
      IEnvironmentVariableService envService, IUserService userService)
    {
      _envOptions = envOptions;
      _envService = envService;
      _userService = userService;
    }

    [HttpGet("signin")]
    public async Task<ActionResult> GetGoogleSignInAsync()
    {
      var googleAuthenticationFile = await _envService.GetEnvironmentVariableValueAsync(_envOptions.Value.GoogleAuthentication);
      if (googleAuthenticationFile == null)
        throw new Exception("Could not find the actual google authentication file.");

      var googleAuthentication = JsonConvert.DeserializeObject<OAuth2Credentials>(googleAuthenticationFile);
      var redirectUri = googleAuthentication.RedirectUris.FirstOrDefault();
      var properties = new AuthenticationProperties
      {
        RedirectUri = Url.Action("GoogleResponseAsync")
      };
      return Challenge(properties, GoogleDefaults.AuthenticationScheme);
    }

    [HttpGet("response")]
    public async Task<ActionResult> GoogleResponseAsync()
    {
      Console.WriteLine("in response");
      var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
      if (!result.Succeeded)
        return Unauthorized();
      Debug.WriteLine(JsonConvert.SerializeObject(result));
      var userLinkDto = new UserLinkDto();
      var claims = result.Principal.Identities.FirstOrDefault().Claims.Select(claim => new
      {
        claim.Issuer,
        claim.OriginalIssuer,
        claim.Type,
        claim.Value,
      });
      claims.ForAll(claim =>
      {
        var claimType = Constants.GoogleClaimsDict.GetValueOrDefault(claim.Type);
        var dtoProp = claimType != null ? userLinkDto.GetType().GetProperty(claimType) : null;
        if (dtoProp != null)
          dtoProp.SetValue(userLinkDto, claim.Value);
      });
      return Ok();
    }
}

问题解答

1. 是否应回到https://localhost:4200/api/google/response方案排查接口未触发?

不建议优先选择这个方案,先解决默认方案(使用/signin-google)的核心问题更高效。如果要排查自定义回调的问题,核心原因是:你在Challenge时设置的RedirectUri会覆盖GoogleOptions.CallbackPath的作用——Google OAuth回调到CallbackPath后,ASP.NET认证中间件会自动完成凭证校验、生成Cookie等操作,之后直接跳转到你设置的RedirectUri指向的接口,所以实际触发的是GoogleResponseAsync而非CallbackPath对应的地址,你不需要为CallbackPath编写接口。

2. 是否需要添加/signin-google路由?

不需要手动添加。/signin-google是ASP.NET OAuth认证中间件内置的回调地址,当未指定GoogleOptions.CallbackPath时,中间件会自动注册该路由并处理Google的回调请求,完成凭证校验、Claims生成、Cookie创建等操作,之后再跳转到Challenge时设置的RedirectUri。

3. 为什么多数教程无需配置就能正常工作?

你的代码存在**重复调用AddAuthentication**的错误:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
 .AddCookie(...);

services.AddAuthentication().AddGoogle(...);

第二次调用AddAuthentication()会重置之前的认证配置,导致默认的Cookie认证方案被覆盖,Google认证的配置也未与Cookie认证关联。正确写法是在同一个AddAuthentication链中添加Google认证:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
 .AddCookie(options =>
  {
    this.SetUpCookieAuthentication(options);
  })
 .AddGoogle(options =>
  {
    this.SetUpGoogleAuthentication(options);
  });

修正后,中间件会正确使用默认Cookie方案,内置的/signin-google回调路由也会正常注册,此时只需在Google控制台配置https://localhost:4200/signin-google即可正常工作,无需手动添加路由或修改CallbackPath。另外你在GetGoogleSignInAsync中设置的RedirectUri是正确的,认证完成后会自动跳转到GoogleResponseAsync接口获取用户信息。


内容的提问来源于stack exchange,提问作者Tonys Ansonī Misirgis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:07:09