如何捕获Asp.net Core 3中Google API授权失败异常、清除Cookie并重新请求授权
解决方案:处理Google API授权失效后的重新授权流程
你的问题核心在于清除Cookie后没有正确触发重新授权流程,而且在当前请求内直接重试API调用是无效的——因为删除Cookie的操作是在响应中设置的,此时浏览器还没收到这个响应,auth.GetCredentialAsync()仍然会拿到内存中缓存的旧凭证,自然会再次抛出401错误。
下面是正确的处理方式:
步骤1:精准捕获授权失效异常并清除认证Cookie
不要删除所有Cookie,只需要删除ASP.NET Core认证系统使用的Cookie(默认名称是CookieAuthenticationDefaults.CookieName),这样更安全。同时,判断异常确实是401凭证无效的情况,避免误处理其他Google API错误。
步骤2:触发重新授权挑战
清除Cookie后,返回ChallengeResult,让ASP.NET Core的认证系统自动跳转到Google的授权页面,完成重新授权后再重定向回原页面。
修改后的控制器代码
[GoogleScopedAuthorize(PeopleServiceService.ScopeConstants.UserinfoProfile)] public async Task<IActionResult> UserProfile([FromServices] IGoogleAuthProvider auth) { try { var cred = await auth.GetCredentialAsync(); var service = new PeopleServiceService(new BaseClientService.Initializer() { HttpClientInitializer = cred }); var request = service.People.Get("people/me"); request.PersonFields = "names,emailAddresses"; var person = await request.ExecuteAsync(); return View(person); } catch (GoogleApiException e) { // 判断是否是凭证无效的401错误 if (e.HttpStatusCode == HttpStatusCode.Unauthorized && e.Error.Errors.Any(err => err.Reason == "authError")) { // 清除认证Cookie Response.Cookies.Delete(CookieAuthenticationDefaults.CookieName); // 触发重新授权,授权完成后重定向回当前页面 return Challenge( new AuthenticationProperties { RedirectUri = Url.Action(nameof(UserProfile)) }, GoogleOpenIdConnectDefaults.AuthenticationScheme); } // 其他Google API错误,抛出或自定义处理 throw; } }
为什么你的原有代码无效?
你在catch中删除Cookie后立刻重试API调用,此时:
- 删除Cookie的指令还在响应中,浏览器尚未接收并执行,所以客户端的Cookie还存在
auth.GetCredentialAsync()会从当前请求的Cookie或内存缓存中获取旧凭证,导致再次调用API失败
必须通过ChallengeResult让用户重定向到Google授权页面,完成新的授权流程,才能获取有效的新凭证。
进阶:全局异常处理(可选)
如果多个控制器都需要处理这种情况,可以在Program.cs(.NET 6+)中配置全局异常处理中间件,统一捕获401的GoogleApiException:
// .NET 6+ Program.cs示例 app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>(); var exception = exceptionHandlerPathFeature?.Error; if (exception is GoogleApiException googleEx && googleEx.HttpStatusCode == HttpStatusCode.Unauthorized && googleEx.Error.Errors.Any(err => err.Reason == "authError")) { // 清除认证Cookie context.Response.Cookies.Delete(CookieAuthenticationDefaults.CookieName); // 触发重新授权 await context.ChallengeAsync( GoogleOpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties { RedirectUri = context.Request.Path }); } }); });
这样就不用在每个控制器方法中重复编写异常处理代码了。
内容的提问来源于stack exchange,提问作者Linda Lawton - DaImTo
相关产品推荐
相关产品推荐

