diff --git a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpSignalRUserIdProvider.cs b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpSignalRUserIdProvider.cs index 10d986933d..71abc1cc54 100644 --- a/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpSignalRUserIdProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.SignalR/Volo/Abp/AspNetCore/SignalR/AbpSignalRUserIdProvider.cs @@ -1,21 +1,28 @@ using Microsoft.AspNetCore.SignalR; using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.SignalR { public class AbpSignalRUserIdProvider : IUserIdProvider, ITransientDependency { - public ICurrentUser CurrentUser { get; } - - public AbpSignalRUserIdProvider(ICurrentUser currentUser) + private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; + + private readonly ICurrentUser _currentUser; + + public AbpSignalRUserIdProvider(ICurrentPrincipalAccessor currentPrincipalAccessor, ICurrentUser currentUser) { - CurrentUser = currentUser; + _currentPrincipalAccessor = currentPrincipalAccessor; + _currentUser = currentUser; } public virtual string GetUserId(HubConnectionContext connection) { - return CurrentUser.Id?.ToString(); + using (_currentPrincipalAccessor.Change(connection.User)) + { + return _currentUser.Id?.ToString(); + } } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/HttpContextCurrentPrincipalAccessor.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/HttpContextCurrentPrincipalAccessor.cs index d1318e2c3e..3e21c04538 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/HttpContextCurrentPrincipalAccessor.cs +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/HttpContextCurrentPrincipalAccessor.cs @@ -6,13 +6,16 @@ namespace Volo.Abp.AspNetCore.Security.Claims { public class HttpContextCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor { - public override ClaimsPrincipal Principal => _httpContextAccessor.HttpContext?.User ?? base.Principal; - private readonly IHttpContextAccessor _httpContextAccessor; public HttpContextCurrentPrincipalAccessor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } + + public override ClaimsPrincipal GetClaimsPrincipal() + { + return _httpContextAccessor.HttpContext?.User ?? base.GetClaimsPrincipal(); + } } } diff --git a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ICurrentPrincipalAccessor.cs b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ICurrentPrincipalAccessor.cs index d49e61ddd6..c510765006 100644 --- a/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ICurrentPrincipalAccessor.cs +++ b/framework/src/Volo.Abp.Security/Volo/Abp/Security/Claims/ICurrentPrincipalAccessor.cs @@ -1,9 +1,12 @@ -using System.Security.Claims; +using System; +using System.Security.Claims; namespace Volo.Abp.Security.Claims { public interface ICurrentPrincipalAccessor { ClaimsPrincipal Principal { get; } + + IDisposable Change(ClaimsPrincipal principal); } } 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 de0032c51d..a4809631fd 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 @@ -1,4 +1,5 @@ -using System.Security.Claims; +using System; +using System.Security.Claims; using System.Threading; using Volo.Abp.DependencyInjection; @@ -6,6 +7,28 @@ namespace Volo.Abp.Security.Claims { public class ThreadCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency { - public virtual ClaimsPrincipal Principal => Thread.CurrentPrincipal as ClaimsPrincipal; + public ClaimsPrincipal Principal => _currentPrincipal.Value ?? GetClaimsPrincipal(); + + private readonly AsyncLocal _currentPrincipal = new AsyncLocal(); + + public virtual ClaimsPrincipal GetClaimsPrincipal() + { + return Thread.CurrentPrincipal as ClaimsPrincipal; + } + + public virtual IDisposable Change(ClaimsPrincipal principal) + { + return SetCurrent(principal); + } + + private IDisposable SetCurrent(ClaimsPrincipal principal) + { + var parent = Principal; + _currentPrincipal.Value = principal; + return new DisposeAction(() => + { + _currentPrincipal.Value = parent; + }); + } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs index b9caa1d7cb..5ee6ec5c1f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakeAuthenticationMiddleware.cs @@ -29,4 +29,4 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization await next(context); } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Test.cs b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Test.cs new file mode 100644 index 0000000000..7a7671215d --- /dev/null +++ b/framework/test/Volo.Abp.Security.Tests/Volo/Abp/Security/Claims/CurrentPrincipalAccessor_Test.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Security.Claims; +using Shouldly; +using Volo.Abp.Testing; +using Xunit; + +namespace Volo.Abp.Security.Claims +{ + public class CurrentPrincipalAccessor_Test : AbpIntegratedTest + { + private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; + + public CurrentPrincipalAccessor_Test() + { + _currentPrincipalAccessor = GetRequiredService(); + } + + [Fact] + public void Should_Get_Changed_Principal_If() + { + var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim(ClaimTypes.Name,"bob"), + new Claim(ClaimTypes.NameIdentifier,"123456") + })); + + var claimsPrincipal2 = new ClaimsPrincipal(new ClaimsIdentity(new List + { + new Claim(ClaimTypes.Name,"lee"), + new Claim(ClaimTypes.NameIdentifier,"654321") + })); + + + _currentPrincipalAccessor.Principal.ShouldBe(null); + + using (_currentPrincipalAccessor.Change(claimsPrincipal)) + { + _currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); + + using (_currentPrincipalAccessor.Change(claimsPrincipal2)) + { + _currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal2); + } + + _currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); + } + _currentPrincipalAccessor.Principal.ShouldBeNull(); + } + } +} diff --git a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs index ef00c20a24..a6d9aae833 100644 --- a/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs +++ b/templates/app/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs @@ -6,9 +6,13 @@ using Volo.Abp.Security.Claims; namespace MyCompanyName.MyProjectName.Security { [Dependency(ReplaceServices = true)] - public class FakeCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency + public class FakeCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor { - public ClaimsPrincipal Principal => GetPrincipal(); + public override ClaimsPrincipal GetClaimsPrincipal() + { + return GetPrincipal(); + } + private ClaimsPrincipal _principal; private ClaimsPrincipal GetPrincipal() @@ -36,4 +40,4 @@ namespace MyCompanyName.MyProjectName.Security return _principal; } } -} \ No newline at end of file +} diff --git a/templates/module/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs b/templates/module/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs index 4196dd09e1..a6d9aae833 100644 --- a/templates/module/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs +++ b/templates/module/aspnet-core/test/MyCompanyName.MyProjectName.TestBase/Security/FakeCurrentPrincipalAccessor.cs @@ -6,9 +6,13 @@ using Volo.Abp.Security.Claims; namespace MyCompanyName.MyProjectName.Security { [Dependency(ReplaceServices = true)] - public class FakeCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency + public class FakeCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor { - public ClaimsPrincipal Principal => GetPrincipal(); + public override ClaimsPrincipal GetClaimsPrincipal() + { + return GetPrincipal(); + } + private ClaimsPrincipal _principal; private ClaimsPrincipal GetPrincipal()