diff --git a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs index d49f389e9..54d45ee68 100644 --- a/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs +++ b/aspnet-core/services/account/AuthServer.Host/AuthIdentityServerModule.cs @@ -151,6 +151,8 @@ namespace AuthServer.Host options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; }); + context.Services.ConfigureNonBreakingSameSiteCookies(); + // context.Services.AddAuthentication(); context.Services.AddAuthentication() .AddJwtBearer(options => @@ -208,7 +210,8 @@ namespace AuthServer.Host app.UseHsts(); } - // app.UseHttpsRedirection(); //TODO: 不启用则不能用MVC方式登录? + // app.UseHttpsRedirection(); + app.UseCookiePolicy(); app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); diff --git a/aspnet-core/services/account/AuthServer.Host/Microsoft/Extensions/DependencyInjection/SameSiteCookiesServiceCollectionExtensions.cs b/aspnet-core/services/account/AuthServer.Host/Microsoft/Extensions/DependencyInjection/SameSiteCookiesServiceCollectionExtensions.cs new file mode 100644 index 000000000..b7a2b72bb --- /dev/null +++ b/aspnet-core/services/account/AuthServer.Host/Microsoft/Extensions/DependencyInjection/SameSiteCookiesServiceCollectionExtensions.cs @@ -0,0 +1,157 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using System; + +/* + * See: https://community.abp.io/articles/patch-for-chrome-login-issue-identityserver4-samesite-cookie-problem-weypwp3n + */ + +namespace Microsoft.Extensions.DependencyInjection +{ + public static class SameSiteCookiesServiceCollectionExtensions + { + /// + /// -1 defines the unspecified value, which tells ASPNET Core to NOT + /// send the SameSite attribute. With ASPNET Core 3.1 the + /// enum will have a definition for + /// Unspecified. + /// + private const SameSiteMode Unspecified = (SameSiteMode)(-1); + + /// + /// Configures a cookie policy to properly set the SameSite attribute + /// for Browsers that handle unknown values as Strict. Ensure that you + /// add the + /// into the pipeline before sending any cookies! + /// + /// + /// Minimum ASPNET Core Version required for this code: + /// - 2.1.14 + /// - 2.2.8 + /// - 3.0.1 + /// - 3.1.0-preview1 + /// Starting with version 80 of Chrome (to be released in February 2020) + /// cookies with NO SameSite attribute are treated as SameSite=Lax. + /// In order to always get the cookies send they need to be set to + /// SameSite=None. But since the current standard only defines Lax and + /// Strict as valid values there are some browsers that treat invalid + /// values as SameSite=Strict. We therefore need to check the browser + /// and either send SameSite=None or prevent the sending of SameSite=None. + /// Relevant links: + /// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1 + /// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00 + /// - https://www.chromium.org/updates/same-site + /// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/ + /// - https://bugs.webkit.org/show_bug.cgi?id=198181 + /// + /// The service collection to register into. + /// The modified . + public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services) + { + services.Configure(options => + { + options.MinimumSameSitePolicy = Unspecified; + options.OnAppendCookie = cookieContext => + CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + options.OnDeleteCookie = cookieContext => + CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); + }); + + return services; + } + + private static void CheckSameSite(HttpContext httpContext, CookieOptions options) + { + if (options.SameSite == SameSiteMode.None) + { + var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); + + if (DisallowsSameSiteNone(userAgent)) + { + options.SameSite = Unspecified; + } + } + } + + /// + /// Checks if the UserAgent is known to interpret an unknown value as Strict. + /// For those the property should be + /// set to . + /// + /// + /// This code is taken from Microsoft: + /// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/ + /// + /// The user agent string to check. + /// Whether the specified user agent (browser) accepts SameSite=None or not. + private 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. + // Notes from Thinktecture: + // Regarding https://caniuse.com/#search=samesite iOS versions lower + // than 12 are not supporting SameSite at all. Starting with version 13 + // unknown values are NOT treated as strict anymore. Therefore we only + // need to check version 12. + 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. + // Notes from Thinktecture: + // Regarding https://caniuse.com/#search=samesite MacOS X versions lower + // than 10.14 are not supporting SameSite at all. Starting with version + // 10.15 unknown values are NOT treated as strict anymore. Therefore we + // only need to check version 10.14. + if (userAgent.Contains("Safari") + && userAgent.Contains("Macintosh; Intel Mac OS X 10_14") + && userAgent.Contains("Version/")) + { + 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. + // Notes from Thinktecture: + // We can not validate this assumption, but we trust Microsofts + // evaluation. And overall not sending a SameSite value equals to the same + // behavior as SameSite=None for these old versions anyways. + if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6")) + { + return true; + } + + if (GetChromeVersion(userAgent) >= 80) + { + return true; + } + + return false; + } + + private static int GetChromeVersion(string userAgent) + { + try + { + return Convert.ToInt32(userAgent.Split("Chrome/")[1].Split('.')[0]); + } + catch (Exception) + { + return 0; + } + } + } +}