diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/AuthClient.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/AuthClient.cs index afb7c8071..f925f3464 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/AuthClient.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/AuthClient.cs @@ -10,6 +10,7 @@ public AuthClient(ICallerProvider callerProvider) UserService = new UserService(callerProvider); SubjectService = new SubjectService(callerProvider); TeamService = new TeamService(callerProvider); + PermissionService = new PermissionService(callerProvider); } public IUserService UserService { get; } @@ -17,5 +18,7 @@ public AuthClient(ICallerProvider callerProvider) public ISubjectService SubjectService { get; } public ITeamService TeamService { get; } + + public IPermissionService PermissionService { get; } } diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Constants.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Constants.cs index 80697e333..43bb0f175 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Constants.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Constants.cs @@ -1,7 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth; internal class Constants { public const string DEFAULT_CLIENT_NAME = "masa.contrib.basicability.auth"; + + public const string ENVIRONMENT_KEY = "env_key"; } diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/EnvironmentProvider.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/EnvironmentProvider.cs new file mode 100644 index 000000000..a9db17500 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/EnvironmentProvider.cs @@ -0,0 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth; + +public class EnvironmentProvider : IEnvironmentProvider +{ + public string GetEnvironment() + { + return "development"; + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/HttpEnvironmentDelegatingHandler.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/HttpEnvironmentDelegatingHandler.cs new file mode 100644 index 000000000..bca846c8e --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/HttpEnvironmentDelegatingHandler.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth; + +public class HttpEnvironmentDelegatingHandler : DelegatingHandler +{ + readonly IHttpContextAccessor _httpContextAccessor; + readonly IEnvironmentProvider _environmentProvider; + + public HttpEnvironmentDelegatingHandler(IHttpContextAccessor httpContextAccessor, IEnvironmentProvider environmentProvider) + { + _httpContextAccessor = httpContextAccessor; + _environmentProvider = environmentProvider; + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var envClaim = _httpContextAccessor.HttpContext?.User.Claims.FirstOrDefault(c => c.Type == "env"); + if (envClaim != null) + { + _httpContextAccessor.HttpContext?.Items.TryAdd(ENVIRONMENT_KEY, _environmentProvider.GetEnvironment()); + request.Headers.Add(ENVIRONMENT_KEY, _environmentProvider.GetEnvironment()); + } + return await base.SendAsync(request, cancellationToken); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/BaseSingleton.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/BaseSingleton.cs new file mode 100644 index 000000000..7bad57808 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/BaseSingleton.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth.Infrastructure; + +public class BaseSingleton +{ + static BaseSingleton() + { + AllSingletons = new Dictionary(); + } + + public static IDictionary AllSingletons { get; } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/Singleton.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/Singleton.cs new file mode 100644 index 000000000..91cba8f89 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/Singleton.cs @@ -0,0 +1,19 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth.Infrastructure; + +public class Singleton : BaseSingleton +{ + static T instance; + + public static T Instance + { + get => instance; + set + { + instance = value; + AllSingletons[typeof(T)] = value; + } + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Masa.Contrib.BasicAbility.Auth.csproj b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Masa.Contrib.BasicAbility.Auth.csproj index 9956dedab..8b8c42b2c 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Masa.Contrib.BasicAbility.Auth.csproj +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Masa.Contrib.BasicAbility.Auth.csproj @@ -9,6 +9,8 @@ + + diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/PermissionService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/PermissionService.cs new file mode 100644 index 000000000..f0c755338 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/PermissionService.cs @@ -0,0 +1,35 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth.Service; + +public class PermissionService : IPermissionService +{ + readonly ICallerProvider _callerProvider; + + const string PARTY = "api/permission/"; + + public PermissionService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + //todo remove userId param + public async Task AuthorizedAsync(string appId, string code, Guid userId) + { + var requestUri = $"{PARTY}authorized?appId={appId}&code={code}&userId={userId}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task> GetMenusAsync(string appId, Guid userId) + { + var requestUri = $"{PARTY}menus?appId={appId}&userId={userId}"; + return await _callerProvider.GetAsync>(requestUri, default) ?? new(); + } + + public async Task> GetElementPermissionsAsync(string appId, Guid userId) + { + var requestUri = $"{PARTY}element-permissions?appId={appId}&userId={userId}"; + return await _callerProvider.GetAsync>(requestUri, default) ?? new(); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/SubjectService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/SubjectService.cs index ed6629223..a8edaea95 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/SubjectService.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/SubjectService.cs @@ -1,3 +1,6 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Service; public class SubjectService : ISubjectService diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/TeamService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/TeamService.cs index 0d1f1f683..cbeb92107 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/TeamService.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/TeamService.cs @@ -1,8 +1,12 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Service; public class TeamService : ITeamService { readonly ICallerProvider _callerProvider; + readonly string _party = "api/team/"; public TeamService(ICallerProvider callerProvider) { @@ -11,8 +15,18 @@ public TeamService(ICallerProvider callerProvider) public async Task GetDetailAsync(Guid id) { - var requestUri = $"api/team/deatil"; + var requestUri = $"{_party}detail"; return await _callerProvider.GetAsync(requestUri, new { id }); } + + public async Task> GetListAsync(Guid userId = default) + { + var requestUri = $"{_party}list"; + if (Guid.Empty != userId) + { + requestUri = $"{requestUri}?userId={userId}"; + } + return await _callerProvider.GetAsync>(requestUri) ?? new(); + } } diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/UserService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/UserService.cs index bf7f82101..e538218d7 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/UserService.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/UserService.cs @@ -1,3 +1,6 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Service; public class UserService : IUserService @@ -32,5 +35,17 @@ public async Task> GetListByTeamAsync(Guid teamId) var requestUri = $"api/staff/getListByTeam"; return await _callerProvider.GetAsync>(requestUri, new { id = teamId }) ?? new(); } + + public async Task ValidateCredentialsByAccountAsync(string account, string password) + { + var requestUri = $"api/user/validateByAccount"; + return await _callerProvider.PostAsync(requestUri, new { account = account, password = password }); + } + + public async Task FindByAccountAsync(string account) + { + var requestUri = $"api/user/findByAccount"; + return await _callerProvider.GetAsync(requestUri, new { account = account }) ?? new(); + } } diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/ServiceCollectionExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/ServiceCollectionExtensions.cs index 08103f6f8..3de70f52e 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/ServiceCollectionExtensions.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ - +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. namespace Masa.Contrib.BasicAbility.Auth; @@ -14,7 +15,7 @@ public static IServiceCollection AddAuthClient(this IServiceCollection services, { builder.Name = DEFAULT_CLIENT_NAME; builder.Configure = opt => opt.BaseAddress = new Uri(authServiceBaseAddress); - }); + }).AddHttpMessageHandler(); }); } @@ -22,10 +23,14 @@ public static IServiceCollection AddAuthClient(this IServiceCollection services, { ArgumentNullException.ThrowIfNull(callerOptions, nameof(callerOptions)); + services.AddHttpContextAccessor(); + services.AddScoped(); + services.AddSingleton(); services.AddCaller(callerOptions); services.AddScoped(serviceProvider => { + Singleton.Instance = serviceProvider; var callProvider = serviceProvider.GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME); var authClient = new AuthClient(callProvider); return authClient; diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/_import.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/_import.cs index 6b5af2e41..a4903c6b6 100644 --- a/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/_import.cs +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Auth/_import.cs @@ -4,8 +4,11 @@ global using Masa.BuildingBlocks.BasicAbility.Auth; global using Masa.BuildingBlocks.BasicAbility.Auth.Model; global using Masa.BuildingBlocks.BasicAbility.Auth.Service; +global using Masa.Contrib.BasicAbility.Auth.Infrastructure; global using Masa.Contrib.BasicAbility.Auth.Service; global using Masa.Utils.Caller.Core; global using Masa.Utils.Caller.HttpClient; +global using Microsoft.AspNetCore.Http; +global using Microsoft.Extensions.Caching.Memory; global using Microsoft.Extensions.DependencyInjection; global using static Masa.Contrib.BasicAbility.Auth.Constants; diff --git a/src/BuildingBlocks/MASA.BuildingBlocks b/src/BuildingBlocks/MASA.BuildingBlocks index 9fc538453..ece32e7c7 160000 --- a/src/BuildingBlocks/MASA.BuildingBlocks +++ b/src/BuildingBlocks/MASA.BuildingBlocks @@ -1 +1 @@ -Subproject commit 9fc5384537a4968838b03efb03eb70e4dea5f6f0 +Subproject commit ece32e7c78c6ec594d194b0f35d4b844cb1ec348 diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/BaseAuthTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/BaseAuthTest.cs new file mode 100644 index 000000000..a78c0d33d --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/BaseAuthTest.cs @@ -0,0 +1,16 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth.Tests +{ + public class BaseAuthTest + { + [TestInitialize] + public void Initialize() + { + IServiceCollection service = new ServiceCollection(); + service.AddAuthClient("https://localhost:18102"); + var authClient = service.BuildServiceProvider().GetRequiredService(); + } + } +} diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs new file mode 100644 index 000000000..99e425748 --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs @@ -0,0 +1,49 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Auth.Tests; + +[TestClass] +public class PermissionServiceTest : BaseAuthTest +{ + [TestMethod] + [DataRow("app1", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")] + public async Task TestGetMenusAsync(string appId, string userId) + { + var data = new List(); + var requestUri = $"api/permission/menus?appId={appId}&userId={userId}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.PermissionService.GetMenusAsync(appId, Guid.Parse(userId)); + callerProvider.Verify(provider => provider.GetAsync>(It.IsAny(), default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + [DataRow("app1", "code", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")] + public async Task TestAuthorizedAsync(string appId, string code, string userId) + { + var data = false; + var requestUri = $"api/permission/authorized?code={code}&userId={userId}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.PermissionService.AuthorizedAsync(appId, code, Guid.Parse(userId)); + callerProvider.Verify(provider => provider.GetAsync(It.IsAny(), default), Times.Once); + } + + [TestMethod] + [DataRow("app1", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")] + public async Task TestGetElementPermissionsAsync(string appId, string userId) + { + var data = new List(); + var requestUri = $"api/permission/element-permissions?appId={appId}&userId={userId}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.PermissionService.GetElementPermissionsAsync(appId, Guid.Parse(userId)); + callerProvider.Verify(provider => provider.GetAsync>(It.IsAny(), default), Times.Once); + Assert.IsTrue(result is not null); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/SubjectServiceTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/SubjectServiceTest.cs index fdd5dfc20..6e050d080 100644 --- a/test/Masa.Contrib.BasicAbility.Auth.Tests/SubjectServiceTest.cs +++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/SubjectServiceTest.cs @@ -1,7 +1,10 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Tests; [TestClass] -public class SubjectServiceTest +public class SubjectServiceTest : BaseAuthTest { [TestMethod] public async Task TestGetListAsync() diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/TeamServiceTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/TeamServiceTest.cs index 2464ef77a..72bd858e7 100644 --- a/test/Masa.Contrib.BasicAbility.Auth.Tests/TeamServiceTest.cs +++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/TeamServiceTest.cs @@ -1,14 +1,17 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Tests; [TestClass] -public class TeamServiceTest +public class TeamServiceTest : BaseAuthTest { [TestMethod] - public async Task TestGetListAsync() + public async Task TestGetDetailAsync() { var data = new TeamDetailModel(); Guid teamId = Guid.NewGuid(); - var requestUri = $"api/team/deatil"; + var requestUri = $"api/team/detail"; var callerProvider = new Mock(); callerProvider.Setup(provider => provider.GetAsync(requestUri, It.IsAny(), default)).ReturnsAsync(data).Verifiable(); var authClient = new AuthClient(callerProvider.Object); @@ -16,5 +19,18 @@ public async Task TestGetListAsync() callerProvider.Verify(provider => provider.GetAsync(requestUri, It.IsAny(), default), Times.Once); Assert.IsTrue(result is not null); } + + [TestMethod] + public async Task TestGetListAsync() + { + var data = new List(); + var requestUri = $"api/team/list"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.TeamService.GetListAsync(); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } } diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/UserServiceTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/UserServiceTest.cs index 8a7a768ff..6be9c3309 100644 --- a/test/Masa.Contrib.BasicAbility.Auth.Tests/UserServiceTest.cs +++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/UserServiceTest.cs @@ -1,7 +1,10 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + namespace Masa.Contrib.BasicAbility.Auth.Tests; [TestClass] -public class UserServiceTest +public class UserServiceTest : BaseAuthTest { [TestMethod] public async Task TestAddAsync() @@ -67,5 +70,33 @@ public async Task TestGetListByRoleAsync() callerProvider.Verify(provider => provider.GetAsync>(requestUri, It.IsAny(), default), Times.Once); Assert.IsTrue(result.Count == 1); } + + [TestMethod] + [DataRow("account", "123456")] + public async Task TestValidateCredentialsByAccountAsync(string account, string password) + { + var data = false; + Guid departmentId = Guid.NewGuid(); + var requestUri = $"api/user/validateByAccount"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, It.IsAny(), default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.UserService.ValidateCredentialsByAccountAsync(account, password); + callerProvider.Verify(provider => provider.PostAsync(requestUri, It.IsAny(), default), Times.Once); + } + + [TestMethod] + [DataRow("authount")] + public async Task TestFindByAccountAsync(string account) + { + var data = new UserModel(); + var requestUri = $"api/user/findByAccount"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, It.IsAny(), default)).ReturnsAsync(data).Verifiable(); + var authClient = new AuthClient(callerProvider.Object); + var result = await authClient.UserService.FindByAccountAsync(account); + callerProvider.Verify(provider => provider.GetAsync(requestUri, It.IsAny(), default), Times.Once); + Assert.IsTrue(result is not null); + } }