mirror of https://github.com/abpframework/abp.git
Browse Source
Ignore `OpenIddictAuthorization` navigation changes when creating tokenspull/25829/head
committed by
GitHub
2 changed files with 105 additions and 0 deletions
@ -0,0 +1,104 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using OpenIddict.Abstractions; |
|||
using Shouldly; |
|||
using Volo.Abp.OpenIddict.Applications; |
|||
using Volo.Abp.OpenIddict.Authorizations; |
|||
using Volo.Abp.OpenIddict.Tokens; |
|||
using Volo.Abp.Uow; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.OpenIddict.EntityFrameworkCore; |
|||
|
|||
/* |
|||
* OpenIddict tokens/authorizations reference their parent application/authorization via a |
|||
* foreign key. Creating a child (e.g. a token) must NOT bump the parent aggregate root's |
|||
* ConcurrencyStamp, otherwise concurrent creations under a shared parent collide with a |
|||
* DbUpdateConcurrencyException. AbpOpenIddictEntityFrameworkCoreModule excludes both parents |
|||
* from AbpEntityChangeOptions.IgnoredNavigationEntitySelectors. These tests guard that. |
|||
*/ |
|||
public class AbpOpenIddictEntityChangeOptions_Tests : OpenIddictEntityFrameworkCoreTestBase |
|||
{ |
|||
private readonly AbpOpenIddictTestData _testData; |
|||
|
|||
public AbpOpenIddictEntityChangeOptions_Tests() |
|||
{ |
|||
_testData = ServiceProvider.GetRequiredService<AbpOpenIddictTestData>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Creating_a_token_should_not_bump_the_referenced_application_stamp() |
|||
{ |
|||
var before = await GetApplicationStampAsync(_testData.App1Id); |
|||
|
|||
await CreateTokenAsync(applicationId: _testData.App1Id, authorizationId: null, subject: "app-stamp-test"); |
|||
|
|||
var after = await GetApplicationStampAsync(_testData.App1Id); |
|||
after.ShouldBe(before); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Creating_a_token_should_not_bump_the_referenced_authorization_stamp() |
|||
{ |
|||
var before = await GetAuthorizationStampAsync(_testData.Authorization1Id); |
|||
|
|||
await CreateTokenAsync(applicationId: _testData.App1Id, authorizationId: _testData.Authorization1Id, subject: "authorization-stamp-test"); |
|||
|
|||
var after = await GetAuthorizationStampAsync(_testData.Authorization1Id); |
|||
after.ShouldBe(before); |
|||
} |
|||
|
|||
// Loads the referenced parents into the same DbContext (as the OpenIddict flow does) and
|
|||
// then creates a token, so the navigation-change detection has a tracked parent to act on.
|
|||
private async Task CreateTokenAsync(Guid applicationId, Guid? authorizationId, string subject) |
|||
{ |
|||
using var scope = ServiceProvider.CreateScope(); |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
using var uow = uowManager.Begin(new AbpUnitOfWorkOptions(), requiresNew: true); |
|||
|
|||
var applicationRepository = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationRepository>(); |
|||
var authorizationRepository = scope.ServiceProvider.GetRequiredService<IOpenIddictAuthorizationRepository>(); |
|||
var tokenStore = scope.ServiceProvider.GetRequiredService<IOpenIddictTokenStore<OpenIddictTokenModel>>(); |
|||
|
|||
await applicationRepository.GetAsync(applicationId); |
|||
if (authorizationId.HasValue) |
|||
{ |
|||
await authorizationRepository.GetAsync(authorizationId.Value); |
|||
} |
|||
|
|||
await tokenStore.CreateAsync(new OpenIddictTokenModel |
|||
{ |
|||
Id = Guid.NewGuid(), |
|||
ApplicationId = applicationId, |
|||
AuthorizationId = authorizationId, |
|||
Subject = subject, |
|||
Type = "access_token", |
|||
Status = OpenIddictConstants.Statuses.Valid, |
|||
Payload = "payload-" + subject |
|||
}, CancellationToken.None); |
|||
|
|||
await uow.CompleteAsync(); |
|||
} |
|||
|
|||
private async Task<string> GetApplicationStampAsync(Guid id) |
|||
{ |
|||
using var scope = ServiceProvider.CreateScope(); |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
using var uow = uowManager.Begin(new AbpUnitOfWorkOptions(), requiresNew: true); |
|||
var stamp = (await scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationRepository>().GetAsync(id)).ConcurrencyStamp; |
|||
await uow.CompleteAsync(); |
|||
return stamp; |
|||
} |
|||
|
|||
private async Task<string> GetAuthorizationStampAsync(Guid id) |
|||
{ |
|||
using var scope = ServiceProvider.CreateScope(); |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
using var uow = uowManager.Begin(new AbpUnitOfWorkOptions(), requiresNew: true); |
|||
var stamp = (await scope.ServiceProvider.GetRequiredService<IOpenIddictAuthorizationRepository>().GetAsync(id)).ConcurrencyStamp; |
|||
await uow.CompleteAsync(); |
|||
return stamp; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue