|
|
|
@ -162,6 +162,47 @@ namespace OpenIddict.Stores |
|
|
|
return ListAsync((scopes, values) => Query(scopes, values), names.ToArray(), cancellationToken); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves all the scopes that contain the specified resource.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="resource">The resource associated with the scopes.</param>
|
|
|
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
|
|
/// <returns>
|
|
|
|
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
|
|
/// whose result returns the scopes associated with the specified resource.
|
|
|
|
/// </returns>
|
|
|
|
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync( |
|
|
|
[NotNull] string resource, CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
if (string.IsNullOrEmpty(resource)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The resource cannot be null or empty.", nameof(resource)); |
|
|
|
} |
|
|
|
|
|
|
|
// To optimize the efficiency of the query a bit, only scopes whose stringified
|
|
|
|
// Resources column contains the specified resource are returned. Once the scopes
|
|
|
|
// are retrieved, a second pass is made to ensure only valid elements are returned.
|
|
|
|
// Implementers that use this method in a hot path may want to override this method
|
|
|
|
// to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient.
|
|
|
|
IQueryable<TScope> Query(IQueryable<TScope> scopes, string state) |
|
|
|
=> from scope in scopes |
|
|
|
where scope.Resources.Contains(state) |
|
|
|
select scope; |
|
|
|
|
|
|
|
var builder = ImmutableArray.CreateBuilder<TScope>(); |
|
|
|
|
|
|
|
foreach (var application in await ListAsync((applications, state) => Query(applications, state), resource, cancellationToken)) |
|
|
|
{ |
|
|
|
var resources = await GetResourcesAsync(application, cancellationToken); |
|
|
|
if (resources.Contains(resource, StringComparer.OrdinalIgnoreCase)) |
|
|
|
{ |
|
|
|
builder.Add(application); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return builder.ToImmutable(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Executes the specified query and returns the first element.
|
|
|
|
/// </summary>
|
|
|
|
@ -301,7 +342,8 @@ namespace OpenIddict.Stores |
|
|
|
|
|
|
|
// Note: parsing the stringified resources is an expensive operation.
|
|
|
|
// To mitigate that, the resulting array is stored in the memory cache.
|
|
|
|
var resources = Cache.GetOrCreate("b6148250-aede-4fb9-a621-07c9bcf238c3", entry => |
|
|
|
var key = string.Concat("b6148250-aede-4fb9-a621-07c9bcf238c3", "\x1e", scope.Resources); |
|
|
|
var resources = Cache.GetOrCreate(key, entry => |
|
|
|
{ |
|
|
|
entry.SetPriority(CacheItemPriority.High) |
|
|
|
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
|
|
|