Browse Source

Restore the previous ambient principal when a Change scope is disposed

pull/25752/head
maliming 3 months ago
parent
commit
7a74082d45
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 6
      framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/CurrentPrincipalAccessorBase.cs
  2. 36
      framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs

6
framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/CurrentPrincipalAccessorBase.cs

@ -8,7 +8,7 @@ public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor
{ {
public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal(); public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal();
private readonly AsyncLocal<ClaimsPrincipal> _currentPrincipal = new AsyncLocal<ClaimsPrincipal>(); private readonly AsyncLocal<ClaimsPrincipal?> _currentPrincipal = new AsyncLocal<ClaimsPrincipal?>();
protected abstract ClaimsPrincipal GetClaimsPrincipal(); protected abstract ClaimsPrincipal GetClaimsPrincipal();
@ -19,10 +19,10 @@ public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor
private IDisposable SetCurrent(ClaimsPrincipal principal) private IDisposable SetCurrent(ClaimsPrincipal principal)
{ {
var parent = Principal; var parent = _currentPrincipal.Value;
_currentPrincipal.Value = principal; _currentPrincipal.Value = principal;
return new DisposeAction<ValueTuple<AsyncLocal<ClaimsPrincipal>, ClaimsPrincipal>>(static (state) => return new DisposeAction<ValueTuple<AsyncLocal<ClaimsPrincipal?>, ClaimsPrincipal?>>(static (state) =>
{ {
var (currentPrincipal, parent) = state; var (currentPrincipal, parent) = state;
currentPrincipal.Value = parent; currentPrincipal.Value = parent;

36
framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs

@ -52,4 +52,40 @@ public class CurrentPrincipalAccessor_Tests : AbpIntegratedTest<AbpSecurityTestM
currentPrincipal.Identity.ShouldNotBeNull(); currentPrincipal.Identity.ShouldNotBeNull();
currentPrincipal.Identity.IsAuthenticated.ShouldBeFalse(); currentPrincipal.Identity.IsAuthenticated.ShouldBeFalse();
} }
[Fact]
public void Should_Reflect_Underlying_Source_After_Change_Scope_Disposed()
{
var accessor = new TestCurrentPrincipalAccessor();
var changedPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, "123456")
}));
using (accessor.Change(changedPrincipal))
{
accessor.Principal.ShouldBe(changedPrincipal);
}
// Disposing the Change scope must not pin the accessor to the fallback principal;
// a principal that becomes available afterwards has to be reflected.
var sourcePrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, "654321")
}));
accessor.SourcePrincipal = sourcePrincipal;
accessor.Principal.ShouldBe(sourcePrincipal);
}
private class TestCurrentPrincipalAccessor : CurrentPrincipalAccessorBase
{
public ClaimsPrincipal? SourcePrincipal { get; set; }
protected override ClaimsPrincipal GetClaimsPrincipal()
{
return SourcePrincipal ?? new ClaimsPrincipal(new ClaimsIdentity());
}
}
} }

Loading…
Cancel
Save