|
|
|
@ -201,6 +201,139 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the tokens corresponding to the specified
|
|
|
|
/// subject and associated with the application identifier.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="subject">The subject associated with the token.</param>
|
|
|
|
/// <param name="client">The client associated with the token.</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 tokens corresponding to the subject/client.
|
|
|
|
/// </returns>
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject, |
|
|
|
[NotNull] string client, CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); |
|
|
|
} |
|
|
|
|
|
|
|
IQueryable<TToken> Query(IQueryable<TApplication> applications, IQueryable<TToken> tokens, TKey key, string principal) |
|
|
|
=> from token in tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.Subject == subject |
|
|
|
join application in applications.AsTracking() on token.Application.Id equals application.Id |
|
|
|
where application.Id.Equals(key) |
|
|
|
select token; |
|
|
|
|
|
|
|
return ImmutableArray.CreateRange(await Query(Applications, Tokens, |
|
|
|
ConvertIdentifierFromString(client), subject).ToListAsync(cancellationToken)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the tokens matching the specified parameters.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="subject">The subject associated with the token.</param>
|
|
|
|
/// <param name="client">The client associated with the token.</param>
|
|
|
|
/// <param name="status">The token status.</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 tokens corresponding to the criteria.
|
|
|
|
/// </returns>
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync( |
|
|
|
[NotNull] string subject, [NotNull] string client, |
|
|
|
[NotNull] string status, CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(status)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
|
|
} |
|
|
|
|
|
|
|
IQueryable<TToken> Query(IQueryable<TApplication> applications, |
|
|
|
IQueryable<TToken> tokens, TKey key, string principal, string state) |
|
|
|
=> from token in tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.Subject == subject && |
|
|
|
token.Status == status |
|
|
|
join application in applications.AsTracking() on token.Application.Id equals application.Id |
|
|
|
where application.Id.Equals(key) |
|
|
|
select token; |
|
|
|
|
|
|
|
return ImmutableArray.CreateRange(await Query(Applications, Tokens, |
|
|
|
ConvertIdentifierFromString(client), subject, status).ToListAsync(cancellationToken)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the tokens matching the specified parameters.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="subject">The subject associated with the token.</param>
|
|
|
|
/// <param name="client">The client associated with the token.</param>
|
|
|
|
/// <param name="status">The token status.</param>
|
|
|
|
/// <param name="type">The token type.</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 tokens corresponding to the criteria.
|
|
|
|
/// </returns>
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync( |
|
|
|
[NotNull] string subject, [NotNull] string client, |
|
|
|
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken) |
|
|
|
{ |
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(status)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
|
|
} |
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(type)) |
|
|
|
{ |
|
|
|
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); |
|
|
|
} |
|
|
|
|
|
|
|
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations can't be
|
|
|
|
// filtered using token.Application.Id.Equals(key). To work around this issue,
|
|
|
|
// this compiled query uses an explicit join before applying the equality check.
|
|
|
|
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
|
|
|
|
|
|
|
|
IQueryable<TToken> Query(IQueryable<TApplication> applications, |
|
|
|
IQueryable<TToken> tokens, TKey key, string principal, string state, string kind) |
|
|
|
=> from token in tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.Subject == subject && |
|
|
|
token.Status == status && |
|
|
|
token.Type == type |
|
|
|
join application in applications.AsTracking() on token.Application.Id equals application.Id |
|
|
|
where application.Id.Equals(key) |
|
|
|
select token; |
|
|
|
|
|
|
|
return ImmutableArray.CreateRange(await Query(Applications, Tokens, |
|
|
|
ConvertIdentifierFromString(client), subject, status, type).ToListAsync(cancellationToken)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Retrieves the list of tokens corresponding to the specified application identifier.
|
|
|
|
/// </summary>
|
|
|
|
@ -281,7 +414,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
|
|
|
|
var key = ConvertIdentifierFromString(identifier); |
|
|
|
|
|
|
|
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization) |
|
|
|
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.Id.Equals(key) |
|
|
|
select token).FirstOrDefaultAsync(cancellationToken); |
|
|
|
} |
|
|
|
@ -303,7 +436,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
|
|
} |
|
|
|
|
|
|
|
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization) |
|
|
|
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.ReferenceId == identifier |
|
|
|
select token).FirstOrDefaultAsync(cancellationToken); |
|
|
|
} |
|
|
|
@ -325,7 +458,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
} |
|
|
|
|
|
|
|
return ImmutableArray.CreateRange( |
|
|
|
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization) |
|
|
|
await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() |
|
|
|
where token.Subject == subject |
|
|
|
select token).ToListAsync(cancellationToken)); |
|
|
|
} |
|
|
|
@ -354,7 +487,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
async Task<string> RetrieveApplicationIdAsync() |
|
|
|
{ |
|
|
|
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key) |
|
|
|
=> from element in tokens |
|
|
|
=> from element in tokens.AsTracking() |
|
|
|
where element.Id.Equals(key) && |
|
|
|
element.Application != null |
|
|
|
select element.Application.Id; |
|
|
|
@ -416,7 +549,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
async Task<string> RetrieveAuthorizationIdAsync() |
|
|
|
{ |
|
|
|
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key) |
|
|
|
=> from element in tokens |
|
|
|
=> from element in tokens.AsTracking() |
|
|
|
where element.Id.Equals(key) && |
|
|
|
element.Authorization != null |
|
|
|
select element.Authorization.Id; |
|
|
|
@ -649,7 +782,7 @@ namespace OpenIddict.EntityFrameworkCore |
|
|
|
var query = Tokens.Include(token => token.Application) |
|
|
|
.Include(token => token.Authorization) |
|
|
|
.OrderBy(token => token.Id) |
|
|
|
.AsQueryable(); |
|
|
|
.AsTracking(); |
|
|
|
|
|
|
|
if (offset.HasValue) |
|
|
|
{ |
|
|
|
|