diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs index c98edaef19..e5356da660 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs +++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Security/AbpComponentsClaimsCache.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Components.Web.Security; public class AbpComponentsClaimsCache : IScopedDependency { - public ClaimsPrincipal Principal { get; private set; } = default!; + public ClaimsPrincipal Principal { get; private set; } = new ClaimsPrincipal(new ClaimsIdentity()); private readonly AuthenticationStateProvider? _authenticationStateProvider; 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/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ThreadCurrentPrincipalAccessor.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ThreadCurrentPrincipalAccessor.cs index ab42441f98..99e8536eec 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ThreadCurrentPrincipalAccessor.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ThreadCurrentPrincipalAccessor.cs @@ -8,6 +8,12 @@ public class ThreadCurrentPrincipalAccessor : CurrentPrincipalAccessorBase, ISin { protected override ClaimsPrincipal GetClaimsPrincipal() { - return (Thread.CurrentPrincipal as ClaimsPrincipal)!; + var principal = Thread.CurrentPrincipal; + if (principal == null) + { + return new ClaimsPrincipal(new ClaimsIdentity()); + } + + return principal as ClaimsPrincipal ?? new ClaimsPrincipal(principal); } } 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 bbc18089be..6480af9c74 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 @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Security.Claims; +using System.Threading; using Shouldly; using Volo.Abp.Testing; using Xunit; @@ -30,20 +31,71 @@ 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()); } - _currentPrincipalAccessor.Principal.ShouldBeNull(); } }