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..601ea32021 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 @@ -1,18 +1,13 @@ -using System.Security.Claims; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Volo.Abp.Security.Claims; 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; + CurrentScope.Value = () => httpContextAccessor.HttpContext?.User ?? GetThreadClaimsPrincipal(); } } } 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..f5d763705c 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,11 +1,44 @@ -using System.Security.Claims; +using System; +using System.Security.Claims; using System.Threading; +using System.Xml.Schema; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Security.Claims { public class ThreadCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency { - public virtual ClaimsPrincipal Principal => Thread.CurrentPrincipal as ClaimsPrincipal; + public Guid Id = Guid.NewGuid(); + + public virtual ClaimsPrincipal Principal + { + get => CurrentScope.Value?.Invoke(); + set => CurrentScope.Value = () => value; + } + + protected readonly AsyncLocal> CurrentScope; + + public ThreadCurrentPrincipalAccessor() + { + CurrentScope = new AsyncLocal> + { + Value = GetThreadClaimsPrincipal + }; + } + + protected ClaimsPrincipal GetThreadClaimsPrincipal() + { + return Thread.CurrentPrincipal as ClaimsPrincipal; + } + + public virtual IDisposable Change(ClaimsPrincipal principal) + { + var parentScope = Principal; + Principal = principal; + return new DisposeAction(() => + { + Principal = parentScope; + }); + } } -} \ 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..cb26230b93 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 @@ -4,16 +4,19 @@ using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; namespace Volo.Abp.AspNetCore.Mvc.Authorization { public class FakeAuthenticationMiddleware : IMiddleware, ITransientDependency { private readonly FakeUserClaims _fakeUserClaims; + private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; - public FakeAuthenticationMiddleware(FakeUserClaims fakeUserClaims) + public FakeAuthenticationMiddleware(FakeUserClaims fakeUserClaims, ICurrentPrincipalAccessor currentPrincipalAccessor) { _fakeUserClaims = fakeUserClaims; + _currentPrincipalAccessor = currentPrincipalAccessor; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) @@ -24,9 +27,11 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization { new ClaimsIdentity(_fakeUserClaims.Claims, "FakeSchema") }); + + //_currentPrincipalAccessor.Change(context.User); } 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(); + } + } +}