GitHub OAuth 通过 CORS 阻止的前端代理重定向

Posted

技术标签:

【中文标题】GitHub OAuth 通过 CORS 阻止的前端代理重定向【英文标题】:GitHub OAuth redirect through frontend proxy blocked by CORS 【发布时间】:2021-07-20 02:24:14 【问题描述】:

我想做什么

我有一个带有 webpack 的 JS 前端,我正在将 /api 请求路由到后端服务器,如下所示:

proxy: 
    '/api': 
        target: 'https://[::1]:5001',
        secure: false,
        changeOrigin: true,
    

还有一个 .NET 5 后端,为所有来源、标头和方法启用了 cors。

app.UseCors(x => x
    .AllowAnyOrigin()
    .AllowAnyMethod()
    .AllowAnyHeader());

这个后端正在尝试使用 GitHub 对人员进行身份验证。

services.AddAuthentication(options =>
            
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = "GitHub";
            )
            .AddCookie()
            .AddOAuth("GitHub", options =>
            
                options.ClientId = GitHubConfiguration.ClientId;
                options.ClientSecret = GitHubConfiguration.ClientSecret;
                options.CallbackPath = new PathString("/api/signin-github");
                options.CorrelationCookie.SameSite = SameSiteMode.Lax;

                options.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
                options.TokenEndpoint = "https://github.com/login/oauth/access_token";
                options.UserInformationEndpoint = "https://api.github.com/user";

                options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
                options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
                options.ClaimActions.MapJsonKey("urn:github:login", "login");
                options.ClaimActions.MapJsonKey("urn:github:url", "html_url");
                options.ClaimActions.MapJsonKey("urn:github:avatar", "avatar_url");

                options.Events = new OAuthEvents
                
                    OnCreatingTicket = async context =>
                    
                        var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
                        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);

                        var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
                        response.EnsureSuccessStatusCode();

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

相当标准,据我所知。

为了测试它,我有这个端点

    [ApiController]
    [Route("api/[controller]/[action]")]
    public class AccountController : ControllerBase
    
        [HttpGet]
        public IActionResult Login()
        
            return Challenge(new AuthenticationProperties  RedirectUri = "/" );
        

当我直接在浏览器中调用它时效果很好

https://localhost:5001/api/account/login

但是当我尝试从我的前端 git 那个端点时,我得到了

访问 'https://github.com/login/oauth/authorize?client_id=&scope=&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A5001%2Fapi%2Fsignin-github&state=' (从 'https://localhost:5001/api/account/login' 重定向)来自 'http://localhost:8081' 已被 CORS 策略阻止:否 'Access-Control-Allow-Origin'请求的资源上存在标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

这是来自 fiddler 的基本总结:

GET https://localhost:5001/api/account/login
302 Redirect to https://github.com/login/oauth/authorize?etc

GET https://github.com/login/oauth/authorize?etc
302 Redirect to https://github.com/login?etc

服务器中的日志没有任何异常。

似乎正在发生的是前端 -> 后端工作正常,但随后后端正尝试重定向前端,由于跨源限制,这是不允许的。

我是否正确地认为我需要以某种方式让重定向到达服务器而不是它仍然认为是原点(因为 webpack 开发服务器代理将原点保持为 localhost:8081 即使在请求是代理之后)?如果是这样,我该如何响应前端?

我已经在这个圈子里转了几个小时,所以任何朝着正确方向的推动都会很棒。

干杯,

编辑这里仔细看看导致它的最后一个重定向返回的标头:

GET https://github.com/login/oauth/authorize?client_id=<oauthinfo>
Host: github.com
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36
Accept: */*
Origin: null
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://localhost:8081/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9


HTTP/1.1 302 Found
Server: GitHub.com
Date: Mon, 26 Apr 2021 21:27:40 GMT
Content-Type: text/html; charset=utf-8
Vary: X-PJAX
permissions-policy: interest-cohort=()
Location: https://github.com/login?client_id=<oauthinfo>
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: deny
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Referrer-Policy: origin-when-cross-origin, strict-origin-when-cross-origin
Expect-CT: max-age=2592000, report-uri="https://api.github.com/_private/browser/errors"
Content-Security-Policy: default-src 'none'; base-uri 'self'; block-all-mixed-content; connect-src 'self'
Vary: Accept-Encoding, Accept, X-Requested-With
X-GitHub-Request-Id: D17E:70F9:663C530:5A21FA1:7097304C
Content-Length: 545

【问题讨论】:

【参考方案1】:

您的应用程序似乎正在从 http=>https 来回重定向(302),并且再次进入相同的循环。发出 https 请求并为您的本地端点启用 https。它应该可以工作

【讨论】:

你确定吗?提琴手摘要显示frontend -> backend -> https://github.com/login/oauth/authorize -> 尝试重定向到https://github.com/login,我认为这是前端登录(进入github)会发生的地方? @PotterJam 请参阅此文档github.com/travisghansen/external-auth-server/issues/57 在代理配置中我已经得到了Headers: "Access-Control-Allow-Origin": "*", https: true ,并且https没有任何区别(只是减少了隧道的数量)。我已经用新的提琴手输出更新了我的帖子。 能否把API pls的整个启动代码贴出来? Cors的规则很多,看全图很重要。 @Sergey 这是整个启动文件,它只是通过默认的 Web 服务器 (kestral) gist.github.com/PotterJam/47c9712f60d868f0255078c2f1b7c08b 运行【参考方案2】:

我没有意识到您不能使用常规 fetch GET 进行身份验证流程。

配置正确,正在使用

window.location.href('https://localhost:5001/api/account/login')

在JS中或使用链接如

<a href='https://localhost:5001/api/account/login'>
  Login to GitHub
</a>

解决了我的问题。

原因很简单,但我忽略了一个。您需要直接向服务器发出请求,这样您就可以独立于前端完成整个身份验证流程,从而放弃前端中可能不太安全的任何密钥。

在流程结束时,您将被重定向回前端,并完全通过身份验证。

【讨论】:

以上是关于GitHub OAuth 通过 CORS 阻止的前端代理重定向的主要内容,如果未能解决你的问题,请参考以下文章

Cors 阻止不和谐 oauth2 登录

从原始反应应用程序访问“http://localhost:8000/oauth/token”处的 XMLHttpRequest 已被 CORS 阻止

github oauth 上的 cors 问题

被 CORS 政策阻止 - React - MangoPay

从源“null”访问“http://github/..file.json”处的 XMLHttpRequest 已被 CORS 策略阻止:

Laravel 7 Passport:被 CORS 策略阻止