From 7a74082d4518e888916496b0366fd69ae120a5d3 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 6 Jul 2026 09:55:34 +0800 Subject: [PATCH] Restore the previous ambient principal when a Change scope is disposed --- .../Claims/CurrentPrincipalAccessorBase.cs | 6 ++-- .../Claims/CurrentPrincipalAccessor_Tests.cs | 36 +++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/CurrentPrincipalAccessorBase.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/CurrentPrincipalAccessorBase.cs index 1d3e296e38..48e9801049 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/CurrentPrincipalAccessorBase.cs +++ b/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(); - private readonly AsyncLocal _currentPrincipal = new AsyncLocal(); + private readonly AsyncLocal _currentPrincipal = new AsyncLocal(); protected abstract ClaimsPrincipal GetClaimsPrincipal(); @@ -19,10 +19,10 @@ public abstract class CurrentPrincipalAccessorBase : ICurrentPrincipalAccessor private IDisposable SetCurrent(ClaimsPrincipal principal) { - var parent = Principal; + var parent = _currentPrincipal.Value; _currentPrincipal.Value = principal; - return new DisposeAction, ClaimsPrincipal>>(static (state) => + return new DisposeAction, ClaimsPrincipal?>>(static (state) => { var (currentPrincipal, parent) = state; currentPrincipal.Value = parent; diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs index 959f605bc4..ed4e6e49ee 100644 --- a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Tests.cs @@ -52,4 +52,40 @@ public class CurrentPrincipalAccessor_Tests : AbpIntegratedTest + { + 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 + { + 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()); + } + } }