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

OAuth2授权后重定向陷入循环问题求助

OAuth2授权完成后无法跳转到指定页面,始终重定向回授权流程

问题根源

你在OnCreatingTicket事件中直接调用context.Response.Redirect("/Home/Index")的做法是错误的。这个事件处于OAuth认证流程的中间环节,此时系统还未完成用户登录凭证(Cookie)的签发。直接修改响应重定向会跳过后续的认证收尾逻辑,导致用户没有有效的认证Cookie。当用户被临时重定向到Home/Index后,如果该页面需要认证(或全局有授权策略),系统会检测到用户未登录,触发DefaultChallengeScheme,再次跳转到授权页面,形成循环。

解决方案

方案一:通过回调路径的控制器动作处理重定向(推荐,符合MVC模式)

  1. 保留OnCreatingTicket中获取用户信息、保存到数据库的逻辑,移除context.Response.Redirect调用
  2. 在AuthController中新增回调动作,完成认证后再执行重定向

修改Program.cs的OAuth配置:

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = "ExternalProvider";
    })
    .AddCookie()
    .AddOAuth("ExternalProvider", options =>
    {
        // 原有配置...
        options.CallbackPath = new PathString("/auth/callback");

        options.Events.OnCreatingTicket = async context =>
        {
            // 原有的获取用户信息、保存到数据库的逻辑完全保留
            HttpRequestMessage req = new(HttpMethod.Get, context.Options.UserInformationEndpoint);
            req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);

            HttpResponseMessage res = await context.Backchannel.SendAsync(req, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
            res.EnsureSuccessStatusCode();

            var user = JsonDocument.Parse(await res.Content.ReadAsStringAsync()).RootElement;
            context.RunClaimActions(user);

            ApplicationDbContext dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
            int userId = int.Parse(user.GetString("sub"));
            bool userExists = (await dbContext.Users.FirstOrDefaultAsync(u => u.Id == userId)) is not null;

            if (!userExists)
            {
                string username = user.GetString("preferred_username");
                string profilePicture = user.GetString("picture");
                dbContext.Users.Add(new ApplicationUser()
                {
                    Id = userId,
                    Username = username,
                    ProfilePicture = profilePicture
                });
                await dbContext.SaveChangesAsync();
            }

            // 移除这行:context.Response.Redirect("/Home/Index");
        };
    });

在AuthController中添加回调动作:

using Microsoft.AspNetCore.Mvc;

namespace Frontend.Controllers
{
    public class AuthController : Controller
    {
        public IActionResult Login()
        {
            return Challenge("ExternalProvider");
        }

        // 新增回调动作
        public async Task<IActionResult> Callback()
        {
            // 此时OAuth认证已完成,系统已为用户签发认证Cookie
            return RedirectToAction("Index", "Home");
        }
    }
}

方案二:使用OnTicketReceived事件指定重定向目标

如果不想新增控制器动作,可以在OAuth事件中配置OnTicketReceived,直接设置认证完成后的跳转路径:

.AddOAuth("ExternalProvider", options =>
{
    // 原有配置...
    options.CallbackPath = new PathString("/auth/callback");

    options.Events.OnCreatingTicket = async context =>
    {
        // 原有的获取用户信息、保存到数据库的逻辑保留
        // 移除context.Response.Redirect调用
    };

    // 新增OnTicketReceived事件配置
    options.Events.OnTicketReceived = context =>
    {
        context.ReturnUri = "/Home/Index";
        return Task.CompletedTask;
    };
})

额外注意事项

  • 确保Home/Index页面如果需要认证(带有[Authorize]属性),用户在认证流程完成后已持有有效的Cookie
  • 检查全局中间件顺序,确保app.UseAuthentication()在app.UseAuthorization()之前执行

内容的提问来源于stack exchange,提问作者iKingNinja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:32:35