首页 > 解决方案 > ASP.NET Core OAuth 不适用于 Safari

问题描述

我们最近发现 OAuth 的某些东西(包括 facebook/google)在桌面 Safari(12.x 和 13.x)上不起作用。该系统在 Chrome、Firefox 和移动 Safari 上运行良好。

我们不确定它是什么时候坏的,但它在 2 周前还在工作,昨晚它没有工作。

这是我们在 Startup.cs 中配置 OAuth 的地方

.AddFacebook(options => {
                    options.AppId = SecretSettings.GetSecret("FacebookAppId");
                    options.AppSecret = SecretSettings.GetSecret("FacebookAppSecret");
                    options.Scope.Add("email");
                    options.AuthorizationEndpoint = "https://www.facebook.com/v2.8/dialog/oauth";
                    options.TokenEndpoint = "https://graph.facebook.com/v2.8/oauth/access_token";
                    options.BackchannelHttpHandler = new FacebookBackChannelHandler();
                    options.UserInformationEndpoint = "https://graph.facebook.com/v2.8/me?fields=id,name,email,first_name,last_name";
                    options.RemoteAuthenticationTimeout = remoteAuthTimeout;
                    options.SignInScheme = IdentityConstants.ExternalScheme;
                    options.AccessDeniedPath = "/account/login?returnUrl=%2F";
                })
                .AddGoogle(options => {
                    options.ClientId = SecretSettings.GetSecret("GoogleOAuth2ClientId");
                    options.ClientSecret = SecretSettings.GetSecret("GoogleOAuth2ClientSecret");
                    options.RemoteAuthenticationTimeout = remoteAuthTimeout;
                    options.SignInScheme = IdentityConstants.ExternalScheme;
                    options.AccessDeniedPath = "/account/login?returnUrl=%2F";
                })

我们使用以下代码生成挑战:

return Challenge(new AuthenticationProperties { RedirectUri = redirectUrl }, authenticationScheme);

据我们所知,通常的流程是:

  1. 使用 Google 登录,生成挑战令牌
  2. 重定向到google oauth,用户登录并返回
  3. 重定向到 /signin-google(中间件路由)以确认给定的代码
  4. 重定向到sso返回动作,处理用户登录或注册

Chrome 正确地点击了所有这些,但 Safari 卡在 3 上。浏览器没有被重定向回我们的 sso 返回操作,而是被丢弃在网站的主页上。

我检查了所涉及的 url,看起来状态、范围和代码正在正确传递,只是中间件内部发生了一些事情,将用户踢到了网站的根目录。

我们正在使用 ASP.NET Core 3.0

有谁知道可能出了什么问题?或者我们可以探索的途径来解决这个问题?

标签: asp.net-coreoauth-2.0safari

解决方案


我遇到了同样的问题。我使用此处找到的解决方案修复了它:https ://github.com/dotnet/aspnetcore/issues/18362

在 Startup.cs 中添加 SameSite cookie 建议代码:

services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.Unspecified;
    options.OnAppendCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
    options.OnDeleteCookie = cookieContext =>
        CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
});

以及以下方法:

private void CheckSameSite(HttpContext httpContext, CookieOptions options)
{
    if (options.SameSite == SameSiteMode.None)
    {
        var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
        if (DisallowsSameSiteNone(userAgent))
        {
            options.SameSite = SameSiteMode.Unspecified;
        }
    }
}
public static bool DisallowsSameSiteNone(string userAgent)
{
    // Cover all iOS based browsers here. This includes:
    // - Safari on iOS 12 for iPhone, iPod Touch, iPad
    // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
    // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
    // All of which are broken by SameSite=None, because they use the iOS networking
    // stack.
    if (userAgent.Contains("CPU iPhone OS 12") ||
        userAgent.Contains("iPad; CPU OS 12"))
    {
        return true;
    }

    // Cover Mac OS X based browsers that use the Mac OS networking stack. 
    // This includes:
    // - Safari on Mac OS X.
    // This does not include:
    // - Chrome on Mac OS X
    // Because they do not use the Mac OS networking stack.
    if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
        userAgent.Contains("Version/") && userAgent.Contains("Safari"))
    {
        return true;
    }

    // Cover Chrome 50-69, because some versions are broken by SameSite=None, 
    // and none in this range require it.
    // Note: this covers some pre-Chromium Edge versions, 
    // but pre-Chromium Edge does not require SameSite=None.
    if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
    {
        return true;
    }

    return false;
}

这将禁止将相同站点策略发送到与其不兼容的浏览器。


推荐阅读