mirror of https://github.com/abpframework/abp.git
committed by
GitHub
32 changed files with 771 additions and 388 deletions
@ -1,86 +1,16 @@ |
|||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
|
||||
using Duende.IdentityModel.Client; |
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Logging; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.Threading; |
|
||||
|
|
||||
namespace Microsoft.AspNetCore.Authentication.Cookies; |
namespace Microsoft.AspNetCore.Authentication.Cookies; |
||||
|
|
||||
public static class CookieAuthenticationOptionsExtensions |
public static class CookieAuthenticationOptionsExtensions |
||||
{ |
{ |
||||
/// <summary>
|
/// <summary>
|
||||
/// Introspect access token on validating the principal.
|
/// Check the access_token is expired or inactive.
|
||||
/// </summary>
|
/// </summary>
|
||||
/// <param name="options"></param>
|
[Obsolete("Use CheckTokenExpiration method instead.")] |
||||
/// <param name="oidcAuthenticationScheme"></param>
|
|
||||
/// <returns></returns>
|
|
||||
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
||||
{ |
{ |
||||
options.Events.OnValidatePrincipal = async principalContext => |
return options.CheckTokenExpiration(oidcAuthenticationScheme, null, TimeSpan.FromMinutes(1)); |
||||
{ |
|
||||
if (principalContext.Principal == null || principalContext.Principal.Identity == null || !principalContext.Principal.Identity.IsAuthenticated) |
|
||||
{ |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var logger = principalContext.HttpContext.RequestServices.GetRequiredService<ILogger<CookieAuthenticationOptions>>(); |
|
||||
|
|
||||
var accessToken = principalContext.Properties.GetTokenValue("access_token"); |
|
||||
if (!accessToken.IsNullOrWhiteSpace()) |
|
||||
{ |
|
||||
var openIdConnectOptions = await GetOpenIdConnectOptions(principalContext, oidcAuthenticationScheme); |
|
||||
var response = await openIdConnectOptions.Backchannel.IntrospectTokenAsync(new TokenIntrospectionRequest |
|
||||
{ |
|
||||
Address = openIdConnectOptions.Configuration?.IntrospectionEndpoint ?? openIdConnectOptions.Authority!.EnsureEndsWith('/') + "connect/introspect", |
|
||||
ClientId = openIdConnectOptions.ClientId!, |
|
||||
ClientSecret = openIdConnectOptions.ClientSecret, |
|
||||
Token = accessToken |
|
||||
}); |
|
||||
|
|
||||
if (response.IsError) |
|
||||
{ |
|
||||
logger.LogError(response.Error); |
|
||||
await SignOutAsync(principalContext); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
if (!response.IsActive) |
|
||||
{ |
|
||||
logger.LogError("The access_token is not active."); |
|
||||
await SignOutAsync(principalContext); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
logger.LogInformation("The access_token is active."); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
logger.LogError("The access_token is not found in the cookie properties, Please make sure SaveTokens of OpenIdConnectOptions is set as true."); |
|
||||
await SignOutAsync(principalContext); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
return options; |
|
||||
} |
|
||||
|
|
||||
private async static Task<OpenIdConnectOptions> GetOpenIdConnectOptions(CookieValidatePrincipalContext principalContext, string oidcAuthenticationScheme) |
|
||||
{ |
|
||||
var openIdConnectOptions = principalContext.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>().Get(oidcAuthenticationScheme); |
|
||||
if (openIdConnectOptions.Configuration == null && openIdConnectOptions.ConfigurationManager != null) |
|
||||
{ |
|
||||
var cancellationTokenProvider = principalContext.HttpContext.RequestServices.GetRequiredService<ICancellationTokenProvider>(); |
|
||||
openIdConnectOptions.Configuration = await openIdConnectOptions.ConfigurationManager.GetConfigurationAsync(cancellationTokenProvider.Token); |
|
||||
} |
|
||||
|
|
||||
return openIdConnectOptions; |
|
||||
} |
|
||||
|
|
||||
private async static Task SignOutAsync(CookieValidatePrincipalContext principalContext) |
|
||||
{ |
|
||||
principalContext.RejectPrincipal(); |
|
||||
await principalContext.HttpContext.SignOutAsync(principalContext.Scheme.Name); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,84 +1,43 @@ |
|||||
using System; |
using System; |
||||
using System.Globalization; |
|
||||
using System.Linq; |
using System.Linq; |
||||
using System.Text.Json; |
using System.Text.Json; |
||||
using System.Text.Json.Serialization; |
|
||||
using Microsoft.Extensions.Options; |
using Microsoft.Extensions.Options; |
||||
using Volo.Abp.DependencyInjection; |
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Timing; |
using Volo.Abp.Timing; |
||||
|
|
||||
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
||||
|
|
||||
public class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependency |
public class AbpDateTimeConverter : AbpDateTimeConverterBase<DateTime>, ITransientDependency |
||||
{ |
{ |
||||
private readonly IClock _clock; |
public AbpDateTimeConverter( |
||||
private readonly AbpJsonOptions _options; |
IClock clock, |
||||
private bool _skipDateTimeNormalization; |
IOptions<AbpJsonOptions> abpJsonOptions, |
||||
|
ICurrentTimezoneProvider currentTimezoneProvider, |
||||
public AbpDateTimeConverter(IClock clock, IOptions<AbpJsonOptions> abpJsonOptions) |
ITimezoneProvider timezoneProvider) |
||||
|
: base(clock, abpJsonOptions, currentTimezoneProvider, timezoneProvider) |
||||
{ |
{ |
||||
_clock = clock; |
|
||||
_options = abpJsonOptions.Value; |
|
||||
} |
} |
||||
|
|
||||
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
||||
{ |
{ |
||||
_skipDateTimeNormalization = true; |
IsSkipDateTimeNormalization = true; |
||||
return this; |
return this; |
||||
} |
} |
||||
|
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
||||
{ |
{ |
||||
if (_options.InputDateTimeFormats.Any()) |
if (Options.InputDateTimeFormats.Any() && reader.TokenType != JsonTokenType.String) |
||||
{ |
|
||||
if (reader.TokenType == JsonTokenType.String) |
|
||||
{ |
|
||||
foreach (var format in _options.InputDateTimeFormats) |
|
||||
{ |
|
||||
var s = reader.GetString(); |
|
||||
if (DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
|
||||
{ |
|
||||
return Normalize(d1); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
throw new JsonException("Reader's TokenType is not String!"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (reader.TryGetDateTime(out var d3)) |
|
||||
{ |
|
||||
return Normalize(d3); |
|
||||
} |
|
||||
|
|
||||
var dateText = reader.GetString(); |
|
||||
if (!dateText.IsNullOrWhiteSpace()) |
|
||||
{ |
{ |
||||
if (DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d4)) |
throw new JsonException("Reader's TokenType is not String!"); |
||||
{ |
|
||||
return Normalize(d4); |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
throw new JsonException("Can't get datetime from the reader!"); |
return TryReadDateTime(ref reader, out var result) |
||||
|
? result |
||||
|
: throw new JsonException("Can't get datetime from the reader!"); |
||||
} |
} |
||||
|
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) |
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) |
||||
{ |
{ |
||||
if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
WriteDateTime(writer, value); |
||||
{ |
|
||||
writer.WriteStringValue(Normalize(value)); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
writer.WriteStringValue(Normalize(value).ToString(_options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected virtual DateTime Normalize(DateTime dateTime) |
|
||||
{ |
|
||||
return _skipDateTimeNormalization ? dateTime : _clock.Normalize(dateTime); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,116 @@ |
|||||
|
using System; |
||||
|
using System.Globalization; |
||||
|
using System.Linq; |
||||
|
using System.Text.Json; |
||||
|
using System.Text.Json.Serialization; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.Timing; |
||||
|
|
||||
|
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
||||
|
|
||||
|
public abstract class AbpDateTimeConverterBase<T> : JsonConverter<T> |
||||
|
{ |
||||
|
public ILogger<AbpDateTimeConverterBase<T>> Logger { get; set; } |
||||
|
|
||||
|
protected IClock Clock { get; } |
||||
|
protected AbpJsonOptions Options { get; } |
||||
|
protected ICurrentTimezoneProvider CurrentTimezoneProvider { get; } |
||||
|
protected ITimezoneProvider TimezoneProvider { get; } |
||||
|
protected bool IsSkipDateTimeNormalization { get; set; } |
||||
|
|
||||
|
protected AbpDateTimeConverterBase( |
||||
|
IClock clock, |
||||
|
IOptions<AbpJsonOptions> abpJsonOptions, |
||||
|
ICurrentTimezoneProvider currentTimezoneProvider, |
||||
|
ITimezoneProvider timezoneProvider) |
||||
|
{ |
||||
|
Logger = NullLogger<AbpDateTimeConverterBase<T>>.Instance; |
||||
|
|
||||
|
Clock = clock; |
||||
|
CurrentTimezoneProvider = currentTimezoneProvider; |
||||
|
TimezoneProvider = timezoneProvider; |
||||
|
Options = abpJsonOptions.Value; |
||||
|
} |
||||
|
|
||||
|
protected bool TryReadDateTime(ref Utf8JsonReader reader, out DateTime value) |
||||
|
{ |
||||
|
value = default; |
||||
|
|
||||
|
if (Options.InputDateTimeFormats.Any()) |
||||
|
{ |
||||
|
if (reader.TokenType != JsonTokenType.String) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
var s = reader.GetString(); |
||||
|
foreach (var format in Options.InputDateTimeFormats) |
||||
|
{ |
||||
|
if (!DateTime.TryParseExact(s, format, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d1)) |
||||
|
{ |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
value = Normalize(d1); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (reader.TryGetDateTime(out var d2)) |
||||
|
{ |
||||
|
value = Normalize(d2); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
var dateText = reader.GetString(); |
||||
|
if (dateText.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (!DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d3)) |
||||
|
{ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
value = Normalize(d3); |
||||
|
return true; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
protected void WriteDateTime(Utf8JsonWriter writer, DateTime value) |
||||
|
{ |
||||
|
if (Options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
writer.WriteStringValue(Normalize(value)); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
writer.WriteStringValue(Normalize(value).ToString(Options.OutputDateTimeFormat, CultureInfo.CurrentUICulture)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual DateTime Normalize(DateTime dateTime) |
||||
|
{ |
||||
|
if (dateTime.Kind != DateTimeKind.Unspecified || |
||||
|
!Clock.SupportsMultipleTimezone || |
||||
|
CurrentTimezoneProvider.TimeZone.IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
||||
|
} |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone); |
||||
|
dateTime = new DateTimeOffset(dateTime, timezoneInfo.GetUtcOffset(dateTime)).UtcDateTime; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
Logger.LogWarning("Could not convert DateTime with unspecified Kind using timezone '{TimeZone}'.", CurrentTimezoneProvider.TimeZone); |
||||
|
} |
||||
|
|
||||
|
return IsSkipDateTimeNormalization ? dateTime : Clock.Normalize(dateTime); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
|
||||
|
namespace Volo.Abp.Auditing.App.Entities; |
||||
|
|
||||
|
public class AppEntityWithJsonProperty : FullAuditedAggregateRoot<Guid> |
||||
|
{ |
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public JsonPropertyObject Data { get; set; } |
||||
|
|
||||
|
public int Count { get; set; } |
||||
|
|
||||
|
public AppEntityWithJsonProperty() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public AppEntityWithJsonProperty(Guid id, string name) : base(id) |
||||
|
{ |
||||
|
Name = name; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public class JsonPropertyObject : Dictionary<string, object> |
||||
|
{ |
||||
|
} |
||||
Loading…
Reference in new issue