ASP.NET Core认证成功后重定向至原请求端点的实现问题
解决ASP.NET Core外部登录后返回原请求端点的问题
核心逻辑
Cookie认证中间件拦截未认证请求时,会自动将原请求路径以returnUrl参数附加到登录地址。只需在登录流程中传递该参数,最终在回调完成后重定向回原地址即可实现需求。
步骤1:修改Signin方法传递ReturnUrl
更新AccountController的Signin方法,接收returnUrl并将其传入外部认证配置:
[AllowAnonymous] [HttpGet("signin")] public IActionResult Signin(string returnUrl = null) { var callbackUrl = Url.Action(nameof(Callback), "Account", new { returnUrl }); var props = _signInManager.ConfigureExternalAuthenticationProperties( GoogleDefaults.AuthenticationScheme, callbackUrl ); return new ChallengeResult(GoogleDefaults.AuthenticationScheme, props); }
此步骤确保Google登录完成后跳转回Callback时,能携带原请求的路径参数。
步骤2:修改Callback方法完成登录并重定向
在Callback中完成用户登录逻辑后,验证returnUrl合法性并跳转回原端点:
[AllowAnonymous] [HttpGet("callback")] public async Task<IActionResult> Callback(string returnUrl = null) { var loginInfo = await _signInManager.GetExternalLoginInfoAsync(); if (loginInfo == null) { // 登录失败时的默认跳转,可根据业务调整 return RedirectToAction("Index", "Home"); } // 先检查用户是否已存在,避免重复创建 var email = loginInfo.Principal.FindFirstValue(ClaimTypes.Email); var user = await _userManager.FindByEmailAsync(email); if (user == null) { user = new User { Email = email, UserName = email }; await _userManager.CreateAsync(user); } await _signInManager.SignInAsync(user, isPersistent: true, GoogleDefaults.AuthenticationScheme); // 验证地址合法性,防止开放重定向攻击 if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl)) { return Redirect(returnUrl); } // 默认跳转地址,可替换为业务首页 return RedirectToAction(nameof(GetUserProfile)); }
关键注意点:必须用Url.IsLocalUrl(returnUrl)验证地址,避免恶意跳转风险。
步骤3:优化认证服务配置
调整认证配置,简化跳转流程并确保回调地址一致:
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; // 直接将默认挑战方案设为Google,减少一次跳转 options.DefaultChallengeScheme = GoogleDefaults.AuthenticationScheme; }) .AddCookie(options => { options.LoginPath = "/api/v1/account/signin"; options.ReturnUrlParameter = "returnUrl"; }) .AddGoogle(GoogleDefaults.AuthenticationScheme, options => { options.ClientId = GetGoogleClientId(); options.ClientSecret = GetGoogleSecret(); // 确保此地址与控制器Callback路由一致,且已在Google开发者后台配置 options.CallbackPath = "/api/v1/account/callback"; });
流程验证
未认证用户访问GetUserProfile时:
- 授权中间件拦截请求,重定向至
/api/v1/account/signin?returnUrl=/api/v1/account/GetUserProfile - Signin发起Google认证挑战,携带回调地址及
returnUrl - 用户完成Google登录后,跳转回
/api/v1/account/callback?returnUrl=/api/v1/account/GetUserProfile - Callback完成用户登录,验证地址后重定向回
GetUserProfile - 用户已认证,成功获取接口返回内容
内容的提问来源于stack exchange,提问作者Dr. Strangelove
相关产品推荐
相关产品推荐

