Browse Source

Add browser timezone handling and cookie management for unauthenticated users

pull/22236/head
maliming 1 year ago
parent
commit
99ee64b7e8
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 7
      framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js
  2. 11
      framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs
  3. 14
      framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs
  4. 61
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs
  5. 18
      npm/packs/core/src/abp.js
  6. 4
      npm/packs/luxon/src/abp.luxon.js

7
framework/src/Volo.Abp.AspNetCore.Components.Web/wwwroot/libs/abp/js/abp.js

@ -245,4 +245,11 @@ var abp = abp || {};
}
}
}
abp.clock = abp.clock || {};
abp.clock.setBrowserTimeZoneToCookie = function () {
abp.utils.setCookieValue('__timezone', Intl.DateTimeFormat().resolvedOptions().timeZone, new Date(new Date().setFullYear(new Date().getFullYear() + 1)), '/');
}
})();

11
framework/src/Volo.Abp.AspNetCore.Components.WebAssembly/Volo/Abp/AspNetCore/Components/WebAssembly/WebAssemblyCachedApplicationConfigurationClient.cs

@ -26,6 +26,8 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio
protected IJSRuntime JSRuntime { get; }
protected IClock Clock { get; }
public WebAssemblyCachedApplicationConfigurationClient(
AbpApplicationConfigurationClientProxy applicationConfigurationClientProxy,
ApplicationConfigurationCache cache,
@ -33,7 +35,8 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio
ICurrentTimezoneProvider currentTimezoneProvider,
AbpApplicationLocalizationClientProxy applicationLocalizationClientProxy,
ApplicationConfigurationChangedService applicationConfigurationChangedService,
IJSRuntime jsRuntime)
IJSRuntime jsRuntime,
IClock clock)
{
ApplicationConfigurationClientProxy = applicationConfigurationClientProxy;
Cache = cache;
@ -42,6 +45,7 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio
ApplicationLocalizationClientProxy = applicationLocalizationClientProxy;
ApplicationConfigurationChangedService = applicationConfigurationChangedService;
JSRuntime = jsRuntime;
Clock = clock;
}
public virtual async Task InitializeAsync()
@ -76,6 +80,11 @@ public class WebAssemblyCachedApplicationConfigurationClient : ICachedApplicatio
);
CurrentTimezoneProvider.TimeZone = configurationDto.Timing.TimeZone.Iana.TimeZoneName;
if (Clock.SupportsMultipleTimezone && !configurationDto.CurrentUser.IsAuthenticated)
{
await JSRuntime.InvokeVoidAsync("abp.clock.setBrowserTimeZoneToCookie");
}
}
public virtual Task<ApplicationConfigurationDto> GetAsync()

14
framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Timing/AbpTimeZoneMiddleware.cs

@ -7,6 +7,7 @@ using Volo.Abp.AspNetCore.Middleware;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Timing;
using Volo.Abp.Users;
namespace Microsoft.AspNetCore.Timing;
@ -14,7 +15,18 @@ public class AbpTimeZoneMiddleware : AbpMiddlewareBase, ITransientDependency
{
public async override Task InvokeAsync(HttpContext context, RequestDelegate next)
{
var timezone = await GetTimezoneFromRequestAsync(context);
if (!context.RequestServices.GetRequiredService<IClock>().SupportsMultipleTimezone)
{
await next(context);
return;
}
string? timezone = null;
if (!context.RequestServices.GetRequiredService<ICurrentUser>().IsAuthenticated)
{
timezone = await GetTimezoneFromRequestAsync(context);
}
if (timezone.IsNullOrWhiteSpace())
{

61
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Timing/AbpTimeZoneMiddleware_Tests.cs

@ -3,9 +3,13 @@ using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.AspNetCore.Mvc.Authorization;
using Volo.Abp.Security.Claims;
using Volo.Abp.Timing;
using Xunit;
@ -14,10 +18,20 @@ namespace Volo.Abp.AspNetCore.Mvc.Timing;
public class AbpTimeZoneMiddleware_Tests : AspNetCoreMvcTestBase
{
private readonly ICurrentTimezoneProvider _currentTimezoneProvider;
private readonly FakeUserClaims _fakeRequiredService;
public AbpTimeZoneMiddleware_Tests()
{
_currentTimezoneProvider = GetRequiredService<ICurrentTimezoneProvider>();
_fakeRequiredService = GetRequiredService<FakeUserClaims>();
}
protected override void ConfigureServices(IServiceCollection services)
{
services.Configure<AbpClockOptions>(options =>
{
options.Kind = DateTimeKind.Utc;
});
}
[Fact]
@ -61,4 +75,51 @@ public class AbpTimeZoneMiddleware_Tests : AspNetCoreMvcTestBase
result.ShouldBe("Europe/Istanbul");
}
}
[Fact]
public async Task Should_Not_Override_TimeZone_Setting_By_Request_For_Authenticated_User()
{
_fakeRequiredService.Claims.AddRange(new[]
{
new Claim(AbpClaimTypes.UserId, AuthTestController.FakeUserId.ToString())
});
using (_currentTimezoneProvider.Change("Europe/Berlin"))
{
var result = await Client.GetStringAsync("api/timing-test");
result.ShouldBe("UTC");
}
// Query string
using (_currentTimezoneProvider.Change("Europe/Berlin"))
{
var result = await Client.GetStringAsync("api/timing-test?__timezone=Europe/Istanbul");
result.ShouldBe("UTC");
}
// Header
using (_currentTimezoneProvider.Change("Europe/Berlin"))
{
Client.DefaultRequestHeaders.Add("__timezone", "Asia/Shanghai");
var result = await Client.GetStringAsync("api/timing-test");
result.ShouldBe("UTC");
}
// Form
using (_currentTimezoneProvider.Change("Europe/Berlin"))
{
Client.DefaultRequestHeaders.Remove("__timezone");
var result = await Client.PostAsync("api/timing-test", new FormUrlEncodedContent(new[] {new KeyValuePair<string, string>("__timezone", "Europe/Germany")}));
(await result.Content.ReadAsStringAsync()).ShouldBe("UTC");
}
// Cookie
using (_currentTimezoneProvider.Change("Europe/Berlin"))
{
Client.DefaultRequestHeaders.Remove("__timezone");
Client.DefaultRequestHeaders.Add("Cookie", "__timezone=Europe/Istanbul");
var result = await Client.GetStringAsync("api/timing-test");
result.ShouldBe("UTC");
}
}
}

18
npm/packs/core/src/abp.js

@ -823,6 +823,24 @@ var abp = abp || {};
return date.toLocaleString(culture, options);
}
abp.clock.browserTimeZone = function () {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}
abp.clock.trySetBrowserTimeZoneToCookie = true;
abp.clock.setBrowserTimeZoneToCookie = function () {
if (!abp.clock.trySetBrowserTimeZoneToCookie || !abp.clock.supportsMultipleTimezone() || abp.currentUser.isAuthenticated) {
return;
}
abp.utils.setCookieValue('__timezone', abp.clock.browserTimeZone(), new Date(new Date().setFullYear(new Date().getFullYear() + 1)), '/');
}
abp.event.on('abp.configurationInitialized', function () {
abp.clock.setBrowserTimeZoneToCookie();
});
/* FEATURES *************************************************/
abp.features = abp.features || {};

4
npm/packs/luxon/src/abp.luxon.js

@ -95,4 +95,8 @@ var abp = abp || {};
.setLocale(abp.localization.currentCulture.cultureName)
.toLocaleString(options);
}
abp.clock.browserTimeZone = function () {
return luxon.DateTime.local().zoneName;
}
})(jQuery);

Loading…
Cancel
Save