Browse Source

Merge branch 'dev' of github.com:abpframework/abp into feat/4881

pull/5137/head
Arman Ozak 6 years ago
parent
commit
e51382ee83
  1. 212
      docs/en/Community-Articles/2020-08-12-Patch-Chrome-Login-Issue-For-IdentityServer4/POST.md
  2. 1
      framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj
  3. 4
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs
  4. 25
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs
  5. 104
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs
  6. 27
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs
  7. 28
      framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs

212
docs/en/Community-Articles/2020-08-12-Patch-Chrome-Login-Issue-For-IdentityServer4/POST.md

@ -0,0 +1,212 @@
# How to fix the Chrome login issue for the IdentityServer4
## Introduction
When you use HTTP on your Identity Server 4 enabled website, users may not login because of the changes made by Chrome in the version 8x. This occurs when you use HTTP schema in your website. The issue is explained here https://docs.microsoft.com/en-gb/dotnet/core/compatibility/3.0-3.1#http-browser-samesite-changes-impact-authentication
## How to solve it?
### Step-1
Create the below extension in your ***.Web** project.
```csharp
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
namespace Microsoft.Extensions.DependencyInjection
{
public static class SameSiteCookiesServiceCollectionExtensions
{
/// <summary>
/// -1 defines the unspecified value, which tells ASPNET Core to NOT
/// send the SameSite attribute. With ASPNET Core 3.1 the
/// <seealso cref="SameSiteMode" /> enum will have a definition for
/// Unspecified.
/// </summary>
private const SameSiteMode Unspecified = (SameSiteMode)(-1);
/// <summary>
/// Configures a cookie policy to properly set the SameSite attribute
/// for Browsers that handle unknown values as Strict. Ensure that you
/// add the <seealso cref="Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware" />
/// into the pipeline before sending any cookies!
/// </summary>
/// <remarks>
/// 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
/// </remarks>
/// <param name="services">The service collection to register <see cref="CookiePolicyOptions" /> into.</param>
/// <returns>The modified <see cref="IServiceCollection" />.</returns>
public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(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;
}
}
}
/// <summary>
/// Checks if the UserAgent is known to interpret an unknown value as Strict.
/// For those the <see cref="CookieOptions.SameSite" /> property should be
/// set to <see cref="Unspecified" />.
/// </summary>
/// <remarks>
/// This code is taken from Microsoft:
/// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
/// </remarks>
/// <param name="userAgent">The user agent string to check.</param>
/// <returns>Whether the specified user agent (browser) accepts SameSite=None or not.</returns>
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;
}
}
}
}
```
### Step-2
Assume that your project name is *Acme.BookStore*. Then open `AcmeBookStoreWebModule.cs` class.
Add the following line to `ConfigureServices()` method.
```csharp
context.Services.ConfigureNonBreakingSameSiteCookies();
```
### Step-3
Go to`OnApplicationInitialization()` method in `AcmeBookStoreWebModule.cs` add `app.UseCookiePolicy();`
```csharp
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseErrorPage();
app.UseHsts();
}
app.UseCookiePolicy(); //<--- added this --->
//....
}
```
It's all! You are ready to go!
---
Referenced from https://www.thinktecture.com/en/identity/samesite/prepare-your-identityserver/

1
framework/src/Volo.Abp.IdentityModel/Volo.Abp.IdentityModel.csproj

@ -17,6 +17,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityModel" Version="4.3.0" /> <PackageReference Include="IdentityModel" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
<ProjectReference Include="..\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" /> <ProjectReference Include="..\Volo.Abp.MultiTenancy\Volo.Abp.MultiTenancy.csproj" />
<ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" /> <ProjectReference Include="..\Volo.Abp.Threading\Volo.Abp.Threading.csproj" />
</ItemGroup> </ItemGroup>

4
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/AbpIdentityModelModule.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Caching;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -7,7 +8,8 @@ namespace Volo.Abp.IdentityModel
{ {
[DependsOn( [DependsOn(
typeof(AbpThreadingModule), typeof(AbpThreadingModule),
typeof(AbpMultiTenancyModule) typeof(AbpMultiTenancyModule),
typeof(AbpCachingModule)
)] )]
public class AbpIdentityModelModule : AbpModule public class AbpIdentityModelModule : AbpModule
{ {

25
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityClientConfiguration.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using IdentityModel; using IdentityModel;
namespace Volo.Abp.IdentityModel namespace Volo.Abp.IdentityModel
@ -81,21 +82,32 @@ namespace Volo.Abp.IdentityModel
get => this.GetOrDefault(nameof(RequireHttps))?.To<bool>() ?? true; get => this.GetOrDefault(nameof(RequireHttps))?.To<bool>() ?? true;
set => this[nameof(RequireHttps)] = value.ToString().ToLowerInvariant(); set => this[nameof(RequireHttps)] = value.ToString().ToLowerInvariant();
} }
/// <summary>
/// Absolute expiration duration (as seconds) for the access token cache.
/// Default: 1800 seconds (30 minutes)
/// </summary>
public int CacheAbsoluteExpiration
{
get => this.GetOrDefault(nameof(CacheAbsoluteExpiration ))?.To<int>() ?? 60 * 30;
set => this[nameof(CacheAbsoluteExpiration)] = value.ToString(CultureInfo.InvariantCulture);
}
public IdentityClientConfiguration() public IdentityClientConfiguration()
{ {
} }
public IdentityClientConfiguration( public IdentityClientConfiguration(
string authority, string authority,
string scope, string scope,
string clientId, string clientId,
string clientSecret, string clientSecret,
string grantType = OidcConstants.GrantTypes.ClientCredentials, string grantType = OidcConstants.GrantTypes.ClientCredentials,
string userName = null, string userName = null,
string userPassword = null, string userPassword = null,
bool requireHttps = true) bool requireHttps = true,
int cacheAbsoluteExpiration = 60 * 30)
{ {
this[nameof(Authority)] = authority; this[nameof(Authority)] = authority;
this[nameof(Scope)] = scope; this[nameof(Scope)] = scope;
@ -105,6 +117,7 @@ namespace Volo.Abp.IdentityModel
this[nameof(UserName)] = userName; this[nameof(UserName)] = userName;
this[nameof(UserPassword)] = userPassword; this[nameof(UserPassword)] = userPassword;
this[nameof(RequireHttps)] = requireHttps.ToString().ToLowerInvariant(); this[nameof(RequireHttps)] = requireHttps.ToString().ToLowerInvariant();
this[nameof(CacheAbsoluteExpiration)] = cacheAbsoluteExpiration.ToString(CultureInfo.InvariantCulture);
} }
} }
} }

104
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelAuthenticationService.cs

@ -10,6 +10,8 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
@ -26,18 +28,24 @@ namespace Volo.Abp.IdentityModel
protected IHttpClientFactory HttpClientFactory { get; } protected IHttpClientFactory HttpClientFactory { get; }
protected ICurrentTenant CurrentTenant { get; } protected ICurrentTenant CurrentTenant { get; }
protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; } protected IdentityModelHttpRequestMessageOptions IdentityModelHttpRequestMessageOptions { get; }
protected IDistributedCache<IdentityModelTokenCacheItem> TokenCache { get; }
protected IDistributedCache<IdentityModelDiscoveryDocumentCacheItem> DiscoveryDocumentCache { get; }
public IdentityModelAuthenticationService( public IdentityModelAuthenticationService(
IOptions<AbpIdentityClientOptions> options, IOptions<AbpIdentityClientOptions> options,
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
IHttpClientFactory httpClientFactory, IHttpClientFactory httpClientFactory,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions) IOptions<IdentityModelHttpRequestMessageOptions> identityModelHttpRequestMessageOptions,
IDistributedCache<IdentityModelTokenCacheItem> tokenCache,
IDistributedCache<IdentityModelDiscoveryDocumentCacheItem> discoveryDocumentCache)
{ {
ClientOptions = options.Value; ClientOptions = options.Value;
CancellationTokenProvider = cancellationTokenProvider; CancellationTokenProvider = cancellationTokenProvider;
HttpClientFactory = httpClientFactory; HttpClientFactory = httpClientFactory;
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
TokenCache = tokenCache;
DiscoveryDocumentCache = discoveryDocumentCache;
IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value; IdentityModelHttpRequestMessageOptions = identityModelHttpRequestMessageOptions.Value;
Logger = NullLogger<IdentityModelAuthenticationService>.Instance; Logger = NullLogger<IdentityModelAuthenticationService>.Instance;
} }
@ -70,27 +78,34 @@ namespace Volo.Abp.IdentityModel
public virtual async Task<string> GetAccessTokenAsync(IdentityClientConfiguration configuration) public virtual async Task<string> GetAccessTokenAsync(IdentityClientConfiguration configuration)
{ {
var discoveryResponse = await GetDiscoveryResponse(configuration); var cacheKey = CalculateTokenCacheKey(configuration);
if (discoveryResponse.IsError) var tokenCacheItem = await TokenCache.GetAsync(cacheKey);
if (tokenCacheItem == null)
{ {
throw new AbpException($"Could not retrieve the OpenId Connect discovery document! ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}"); var tokenResponse = await GetTokenResponse(configuration);
}
var tokenResponse = await GetTokenResponse(discoveryResponse, configuration);
if (tokenResponse.IsError) if (tokenResponse.IsError)
{
if (tokenResponse.ErrorDescription != null)
{ {
throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}"); if (tokenResponse.ErrorDescription != null)
{
throw new AbpException($"Could not get token from the OpenId Connect server! ErrorType: {tokenResponse.ErrorType}. " +
$"Error: {tokenResponse.Error}. ErrorDescription: {tokenResponse.ErrorDescription}. HttpStatusCode: {tokenResponse.HttpStatusCode}");
}
var rawError = tokenResponse.Raw;
var withoutInnerException = rawError.Split(new string[] { "<eof/>" }, StringSplitOptions.RemoveEmptyEntries);
throw new AbpException(withoutInnerException[0]);
} }
var rawError = tokenResponse.Raw; tokenCacheItem = new IdentityModelTokenCacheItem(tokenResponse.AccessToken);
var withoutInnerException = rawError.Split(new string[] { "<eof/>" }, StringSplitOptions.RemoveEmptyEntries); await TokenCache.SetAsync(cacheKey, tokenCacheItem,
throw new AbpException(withoutInnerException[0]); new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration)
});
} }
return tokenResponse.AccessToken; return tokenCacheItem.AccessToken;
} }
protected virtual void SetAccessToken(HttpClient client, string accessToken) protected virtual void SetAccessToken(HttpClient client, string accessToken)
@ -110,8 +125,33 @@ namespace Volo.Abp.IdentityModel
ClientOptions.IdentityClients.Default; ClientOptions.IdentityClients.Default;
} }
protected virtual async Task<DiscoveryDocumentResponse> GetDiscoveryResponse( protected virtual async Task<string> GetTokenEndpoint(IdentityClientConfiguration configuration)
IdentityClientConfiguration configuration) {
//TODO: Can use (configuration.Authority + /connect/token) directly?
var tokenEndpointUrlCacheKey = CalculateDiscoveryDocumentCacheKey(configuration);
var discoveryDocumentCacheItem = await DiscoveryDocumentCache.GetAsync(tokenEndpointUrlCacheKey);
if (discoveryDocumentCacheItem == null)
{
var discoveryResponse = await GetDiscoveryResponse(configuration);
if (discoveryResponse.IsError)
{
throw new AbpException($"Could not retrieve the OpenId Connect discovery document! " +
$"ErrorType: {discoveryResponse.ErrorType}. Error: {discoveryResponse.Error}");
}
discoveryDocumentCacheItem = new IdentityModelDiscoveryDocumentCacheItem(discoveryResponse.TokenEndpoint);
await DiscoveryDocumentCache.SetAsync(tokenEndpointUrlCacheKey, discoveryDocumentCacheItem,
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(configuration.CacheAbsoluteExpiration)
});
}
return discoveryDocumentCacheItem.TokenEndpoint;
}
protected virtual async Task<DiscoveryDocumentResponse> GetDiscoveryResponse(IdentityClientConfiguration configuration)
{ {
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName)) using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{ {
@ -128,10 +168,10 @@ namespace Volo.Abp.IdentityModel
} }
} }
protected virtual async Task<TokenResponse> GetTokenResponse( protected virtual async Task<TokenResponse> GetTokenResponse(IdentityClientConfiguration configuration)
DiscoveryDocumentResponse discoveryResponse,
IdentityClientConfiguration configuration)
{ {
var tokenEndpoint = await GetTokenEndpoint(configuration);
using (var httpClient = HttpClientFactory.CreateClient(HttpClientName)) using (var httpClient = HttpClientFactory.CreateClient(HttpClientName))
{ {
AddHeaders(httpClient); AddHeaders(httpClient);
@ -140,12 +180,12 @@ namespace Volo.Abp.IdentityModel
{ {
case OidcConstants.GrantTypes.ClientCredentials: case OidcConstants.GrantTypes.ClientCredentials:
return await httpClient.RequestClientCredentialsTokenAsync( return await httpClient.RequestClientCredentialsTokenAsync(
await CreateClientCredentialsTokenRequestAsync(discoveryResponse, configuration), await CreateClientCredentialsTokenRequestAsync(tokenEndpoint, configuration),
CancellationTokenProvider.Token CancellationTokenProvider.Token
); );
case OidcConstants.GrantTypes.Password: case OidcConstants.GrantTypes.Password:
return await httpClient.RequestPasswordTokenAsync( return await httpClient.RequestPasswordTokenAsync(
await CreatePasswordTokenRequestAsync(discoveryResponse, configuration), await CreatePasswordTokenRequestAsync(tokenEndpoint, configuration),
CancellationTokenProvider.Token CancellationTokenProvider.Token
); );
default: default:
@ -154,11 +194,11 @@ namespace Volo.Abp.IdentityModel
} }
} }
protected virtual Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync(DiscoveryDocumentResponse discoveryResponse, IdentityClientConfiguration configuration) protected virtual Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync(string tokenEndpoint, IdentityClientConfiguration configuration)
{ {
var request = new PasswordTokenRequest var request = new PasswordTokenRequest
{ {
Address = discoveryResponse.TokenEndpoint, Address = tokenEndpoint,
Scope = configuration.Scope, Scope = configuration.Scope,
ClientId = configuration.ClientId, ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret, ClientSecret = configuration.ClientSecret,
@ -172,13 +212,11 @@ namespace Volo.Abp.IdentityModel
return Task.FromResult(request); return Task.FromResult(request);
} }
protected virtual Task<ClientCredentialsTokenRequest> CreateClientCredentialsTokenRequestAsync( protected virtual Task<ClientCredentialsTokenRequest> CreateClientCredentialsTokenRequestAsync(string tokenEndpoint, IdentityClientConfiguration configuration)
DiscoveryDocumentResponse discoveryResponse,
IdentityClientConfiguration configuration)
{ {
var request = new ClientCredentialsTokenRequest var request = new ClientCredentialsTokenRequest
{ {
Address = discoveryResponse.TokenEndpoint, Address = tokenEndpoint,
Scope = configuration.Scope, Scope = configuration.Scope,
ClientId = configuration.ClientId, ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret ClientSecret = configuration.ClientSecret
@ -209,5 +247,15 @@ namespace Volo.Abp.IdentityModel
client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString()); client.DefaultRequestHeaders.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
} }
} }
protected virtual string CalculateDiscoveryDocumentCacheKey(IdentityClientConfiguration configuration)
{
return IdentityModelDiscoveryDocumentCacheItem.CalculateCacheKey(configuration);
}
protected virtual string CalculateTokenCacheKey(IdentityClientConfiguration configuration)
{
return IdentityModelTokenCacheItem.CalculateCacheKey(configuration);
}
} }
} }

27
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelDiscoveryDocumentCacheItem.cs

@ -0,0 +1,27 @@
using System;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.IdentityModel
{
[Serializable]
[IgnoreMultiTenancy]
public class IdentityModelDiscoveryDocumentCacheItem
{
public string TokenEndpoint { get; set; }
public IdentityModelDiscoveryDocumentCacheItem()
{
}
public IdentityModelDiscoveryDocumentCacheItem(string tokenEndpoint)
{
TokenEndpoint = tokenEndpoint;
}
public static string CalculateCacheKey(IdentityClientConfiguration configuration)
{
return configuration.Authority.ToLower().ToMd5();
}
}
}

28
framework/src/Volo.Abp.IdentityModel/Volo/Abp/IdentityModel/IdentityModelTokenCacheItem.cs

@ -0,0 +1,28 @@
using System;
using System.Linq;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.IdentityModel
{
[Serializable]
[IgnoreMultiTenancy]
public class IdentityModelTokenCacheItem
{
public string AccessToken { get; set; }
public IdentityModelTokenCacheItem()
{
}
public IdentityModelTokenCacheItem(string accessToken)
{
AccessToken = accessToken;
}
public static string CalculateCacheKey(IdentityClientConfiguration configuration)
{
return string.Join(",", configuration.Select(x => x.Key + ":" + x.Value)).ToMd5();
}
}
}
Loading…
Cancel
Save