ASP.NET Core MVC中Discord OAuth2配置异常求助:授权后未跳转至指定回调Action
问题分析与解决方案
看起来你遇到的核心问题是OAuth认证中间件已经接管了回调路径的处理逻辑,导致你自定义的DiscordSignIn Action根本不会被触发,最终按照默认配置重定向到了Index页面。下面详细拆解原因和解决办法:
为什么自定义回调Action没被触发?
AspNet.Security.OAuth.Providers提供的AddDiscord中间件,会自动拦截你配置的CallbackPath(也就是/signin-discord)请求。当Discord返回授权码后,中间件会先完成以下流程:
- 用授权码交换Access Token
- 调用Discord的用户信息接口获取用户数据
- 生成认证票据(Authentication Ticket)
- 根据你在
Challenge时设置的RedirectUri完成重定向
整个过程完全由中间件在MVC路由之前处理,所以你写的[Route("signin-discord")] Action永远不会被执行。
为什么会重定向到Index?
看你的Index POST方法里的代码:
var challengeResult = Challenge(new AuthenticationProperties { RedirectUri = "/" }, provider);
这里明确设置了认证成功后的重定向地址为根路径/,而根路径对应的就是你的Index GET Action,所以中间件处理完认证后自然会跳转到这里。
正确的处理方式
你不需要自己写回调Action,而是利用中间件提供的扩展点来处理认证后的逻辑,或者调整重定向目标来获取用户信息。
方案1:利用OnCreatingTicket事件处理认证逻辑
在AddDiscord配置中添加OnCreatingTicket事件,这是处理用户信息、添加自定义Claims或保存用户数据的最佳时机:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie() .AddDiscord(o => { o.ClientId = DiscordDefaults.ClientId; o.ClientSecret = DiscordDefaults.ClientSecret; o.CallbackPath = new PathString("/signin-discord"); o.Scope.Add("identify"); o.Scope.Add("email"); // 注意:需要在Discord机器人设置中开启email权限 o.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id", ClaimValueTypes.UInteger64); o.ClaimActions.MapJsonKey(ClaimTypes.Name, "username", ClaimValueTypes.String); o.ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email); // 认证成功后触发的事件,在这里处理自定义逻辑 o.Events.OnCreatingTicket = async context => { // 获取Discord返回的原始用户数据 var userId = context.User.GetProperty("id").GetString(); var username = context.User.GetProperty("username").GetString(); var avatarHash = context.User.GetProperty("avatar").GetString(); Debug.WriteLine($"已认证用户:{username}(ID:{userId})"); // 示例:添加自定义Claim context.Identity.AddClaim(new Claim("DiscordAvatar", avatarHash)); // 示例:将用户信息保存到数据库 // await _userRepository.CreateOrUpdateUser(userId, username, ...); await Task.CompletedTask; }; });
方案2:调整重定向目标,在目标页面获取用户信息
修改Challenge时的RedirectUri,指向专门的成功页面,然后在该页面的Action中获取当前认证用户的信息:
- 修改POST
Index方法的重定向地址:
var challengeResult = Challenge(new AuthenticationProperties { RedirectUri = "/login-success" }, provider);
- 添加
LoginSuccessAction:
public IActionResult LoginSuccess() { // 获取当前已认证的用户信息 var currentUser = HttpContext.User; if (!currentUser.Identity.IsAuthenticated) { return RedirectToAction(nameof(Index)); } var userId = currentUser.FindFirstValue(ClaimTypes.NameIdentifier); var username = currentUser.FindFirstValue(ClaimTypes.Name); var email = currentUser.FindFirstValue(ClaimTypes.Email); var avatar = currentUser.FindFirstValue("DiscordAvatar"); // 对应方案1中添加的自定义Claim Debug.WriteLine($"用户ID:{userId},用户名:{username},邮箱:{email}"); return View(); }
额外注意事项
- 确保Discord机器人OAuth2设置中的回调URL和你配置的
CallbackPath完全一致(例如https://your-domain.com/signin-discord) - 如果需要获取用户邮箱,必须在Discord开发者后台开启
email权限,并且在Scope中添加email - 移除你自定义的
DiscordSignInAction,避免路由冲突
内容的提问来源于stack exchange,提问作者Patrick Schulz
相关产品推荐
相关产品推荐

