在ASP.NET Core中使用Giraffe实现GitHub OAuth流程时出现重定向循环
解决Giraffe中GitHub OAuth的双重API调用与重定向循环问题
我明白你在Giraffe里搭建GitHub OAuth测试应用时遇到了两个棘手的问题:触发OnCreatingTicket事件时会两次调用https://api.github.com/user,而且回调路径/signin-github处理后会莫名重定向到/login形成循环,更奇怪的是重定向好像发生在Giraffe路由处理之前,日志里只看到/login的调用记录。我来帮你一步步拆解问题并给出解决办法:
一、双重调用api.github.com/user的根源
ASP.NET Core的GitHub认证中间件默认会在两个环节调用用户信息接口:
- 当你调用
challenge "GitHub"发起认证请求时,中间件拿到access token后,会自动调用一次api.github.com/user来填充ClaimsPrincipal; - 如果你在
OnCreatingTicket事件里又手动写了调用这个接口的代码(比如想获取更多用户数据),就会导致重复调用。
解决思路:
- 如果你只需要基础的用户信息,直接删掉
OnCreatingTicket里手动调用接口的代码就行,中间件已经帮你搞定了; - 要是需要额外字段,直接用中间件已经获取到的
context.User来提取,或者用context.AccessToken调用一次接口就够了,别重复触发请求。
二、/signin-github回调后重定向循环的排查与解决
你说/signin-github并不要求认证,但还是被重定向到/login,而且重定向在路由处理前就发生了,这大概率是认证中间件的配置顺序或者路由匹配逻辑出了问题,咱们一步步来修正:
可能的原因
- 中间件顺序错了:如果
UseAuthentication放在了UseGiraffe之后,回调请求进来时,路由还没处理就先触发了认证检查,这时候OAuth的临时状态还没处理完,就会被判定为未认证,进而重定向到/login; - 路由匹配优先级不对:你的路由定义里,
mustBeLoggedIn包裹的是/api,但如果/signin-github的路由没被优先匹配到,请求可能落到404或者被错误的认证拦截; - 回调路径配置与路由不匹配:虽然你设置了
options.CallbackPath <- new PathString("/signin-github"),但如果路由里的/signin-github处理逻辑没正确绑定,中间件处理完回调后找不到对应的处理程序,就会触发默认重定向。
具体解决步骤
- 调整中间件加载顺序:一定要把
UseAuthentication和UseAuthorization放在UseGiraffe前面,这样回调请求进来时,认证中间件先处理完OAuth流程,再交给Giraffe路由:
app.UseAuthentication() .UseAuthorization() .UseGiraffe(webApp)
- 修正路由匹配顺序:把不需要认证的路由(比如
/signin-github)放在认证拦截逻辑的前面,确保请求能被优先匹配到:
let webApp = logRequest >> choose [ GET >> choose [ route "/" >> indexHandler "world" route "/login" >> loginHandler route "/signin-github" >> signinHandler ] mustBeLoggedIn >> GET >> choose [ route "/api" >> indexHandler "authenticated world" ] setStatusCode 404 >> text "Not Found" ]
这样/signin-github请求就不会被mustBeLoggedIn的拦截逻辑影响了。
- 简化回调处理逻辑:其实GitHub认证中间件会自动处理
CallbackPath对应的请求,你不需要自己写signinHandler,只要确保注册中间件时配置正确就行:
services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = GitHubDefaults.AuthenticationScheme; }) .AddCookie() .AddGitHub(options => { options.ClientId = "你的ClientId"; options.ClientSecret = "你的ClientSecret"; options.CallbackPath = new PathString("/signin-github"); // 自定义OnCreatingTicket时,避免重复调用用户接口 options.Events = new OAuthEvents { OnCreatingTicket = async context => { // 直接用context.User获取中间件已拿到的用户信息 let userName = context.User.GetProperty("login").GetString(); // 如果需要额外数据,用AccessToken调用一次即可 let httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken); let response = await httpClient.GetAsync("https://api.github.com/user/emails"); response.EnsureSuccessStatusCode(); let emails = await response.Content.ReadFromJsonAsync<JsonElement>(); // 处理额外数据... } }; });
- 检查Cookie认证配置:确保Cookie认证中间件配置正确,回调完成后能生成有效的认证Cookie,这样后续访问
/api时就不会被重定向到/login了。
按照这些步骤调整后,应该就能解决重定向循环和双重API调用的问题了。
内容的提问来源于stack exchange,提问作者Mulder
相关产品推荐
相关产品推荐

