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.Threading.Tasks; |
|||
using Duende.IdentityModel.Client; |
|||
using Microsoft.AspNetCore.Authentication.OpenIdConnect; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.Threading; |
|||
|
|||
namespace Microsoft.AspNetCore.Authentication.Cookies; |
|||
|
|||
public static class CookieAuthenticationOptionsExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Introspect access token on validating the principal.
|
|||
/// Check the access_token is expired or inactive.
|
|||
/// </summary>
|
|||
/// <param name="options"></param>
|
|||
/// <param name="oidcAuthenticationScheme"></param>
|
|||
/// <returns></returns>
|
|||
[Obsolete("Use CheckTokenExpiration method instead.")] |
|||
public static CookieAuthenticationOptions IntrospectAccessToken(this CookieAuthenticationOptions options, string oidcAuthenticationScheme = "oidc") |
|||
{ |
|||
options.Events.OnValidatePrincipal = async principalContext => |
|||
{ |
|||
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); |
|||
return options.CheckTokenExpiration(oidcAuthenticationScheme, null, TimeSpan.FromMinutes(1)); |
|||
} |
|||
} |
|||
|
|||
@ -1,84 +1,43 @@ |
|||
using System; |
|||
using System.Globalization; |
|||
using System.Linq; |
|||
using System.Text.Json; |
|||
using System.Text.Json.Serialization; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.Json.SystemTextJson.JsonConverters; |
|||
|
|||
public class AbpDateTimeConverter : JsonConverter<DateTime>, ITransientDependency |
|||
public class AbpDateTimeConverter : AbpDateTimeConverterBase<DateTime>, ITransientDependency |
|||
{ |
|||
private readonly IClock _clock; |
|||
private readonly AbpJsonOptions _options; |
|||
private bool _skipDateTimeNormalization; |
|||
|
|||
public AbpDateTimeConverter(IClock clock, IOptions<AbpJsonOptions> abpJsonOptions) |
|||
public AbpDateTimeConverter( |
|||
IClock clock, |
|||
IOptions<AbpJsonOptions> abpJsonOptions, |
|||
ICurrentTimezoneProvider currentTimezoneProvider, |
|||
ITimezoneProvider timezoneProvider) |
|||
: base(clock, abpJsonOptions, currentTimezoneProvider, timezoneProvider) |
|||
{ |
|||
_clock = clock; |
|||
_options = abpJsonOptions.Value; |
|||
} |
|||
|
|||
public virtual AbpDateTimeConverter SkipDateTimeNormalization() |
|||
{ |
|||
_skipDateTimeNormalization = true; |
|||
IsSkipDateTimeNormalization = true; |
|||
return this; |
|||
} |
|||
|
|||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
|||
{ |
|||
if (_options.InputDateTimeFormats.Any()) |
|||
{ |
|||
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 (Options.InputDateTimeFormats.Any() && reader.TokenType != JsonTokenType.String) |
|||
{ |
|||
if (DateTime.TryParse(dateText, CultureInfo.CurrentUICulture, DateTimeStyles.None, out var d4)) |
|||
{ |
|||
return Normalize(d4); |
|||
} |
|||
throw new JsonException("Reader's TokenType is not String!"); |
|||
} |
|||
|
|||
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) |
|||
{ |
|||
if (_options.OutputDateTimeFormat.IsNullOrWhiteSpace()) |
|||
{ |
|||
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); |
|||
WriteDateTime(writer, value); |
|||
} |
|||
} |
|||
|
|||
@ -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