From aad4fa53e8d83a40970e8401ecb31c54265b4062 Mon Sep 17 00:00:00 2001
From: Mayue <mayue@lonsid.cn>
Date: Wed, 8 Jun 2022 16:29:14 +0800
Subject: [PATCH 1/2] feat:add sdk method for team and permission

---
 .../AuthClient.cs                             |  3 +
 .../Constants.cs                              |  5 ++
 .../EnvironmentProvider.cs                    | 12 ++++
 .../HttpEnvironmentDelegatingHandler.cs       | 27 +++++++
 .../Infrastructure/BaseSingleton.cs           | 14 ++++
 .../Infrastructure/Singleton.cs               | 19 +++++
 .../Masa.Contrib.BasicAbility.Auth.csproj     |  2 +
 .../Service/PermissionService.cs              | 35 +++++++++
 .../Service/SubjectService.cs                 |  3 +
 .../Service/TeamService.cs                    | 16 ++++-
 .../Service/UserService.cs                    | 15 ++++
 .../ServiceCollectionExtensions.cs            |  9 ++-
 .../Masa.Contrib.BasicAbility.Auth/_import.cs |  3 +
 src/BuildingBlocks/MASA.BuildingBlocks        |  2 +-
 .../BaseAuthTest.cs                           | 16 +++++
 .../PermissionServiceTest.cs                  | 72 +++++++++++++++++++
 .../SubjectServiceTest.cs                     |  5 +-
 .../TeamServiceTest.cs                        | 22 +++++-
 .../UserServiceTest.cs                        | 33 ++++++++-
 19 files changed, 304 insertions(+), 9 deletions(-)
 create mode 100644 src/BasicAbility/Masa.Contrib.BasicAbility.Auth/EnvironmentProvider.cs
 create mode 100644 src/BasicAbility/Masa.Contrib.BasicAbility.Auth/HttpEnvironmentDelegatingHandler.cs
 create mode 100644 src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/BaseSingleton.cs
 create mode 100644 src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Infrastructure/Singleton.cs
 create mode 100644 src/BasicAbility/Masa.Contrib.BasicAbility.Auth/Service/PermissionService.cs
 create mode 100644 test/Masa.Contrib.BasicAbility.Auth.Tests/BaseAuthTest.cs
 create mode 100644 test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs

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<HttpResponseMessage> 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<Type, object>();
+    }
+
+    public static IDictionary<Type, object> 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<T> : 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 @@
   <ItemGroup>
     <PackageReference Include="Masa.Utils.Caller.HttpClient" Version="$(MasaUtilsPackageVersion)" />
     <PackageReference Include="Masa.Utils.Configuration.Json" Version="$(MasaUtilsPackageVersion)" />
+    <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
+    <PackageReference Include="Masa.Utils.Extensions.DependencyInjection" Version="$(MasaUtilsPackageVersion)" />
   </ItemGroup>
 
   <ItemGroup>
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<bool> AuthorizedAsync(string appId, string code, Guid userId)
+    {
+        var requestUri = $"{PARTY}authorized?appId={appId}&code={code}&userId={userId}";
+        return await _callerProvider.GetAsync<bool>(requestUri);
+    }
+
+    public async Task<List<MenuModel>> GetMenusAsync(string appId, Guid userId)
+    {
+        var requestUri = $"{PARTY}menus?appId={appId}&userId={userId}";
+        return await _callerProvider.GetAsync<List<MenuModel>>(requestUri, default) ?? new();
+    }
+
+    public async Task<List<string>> GetElementPermissionsAsync(string appId, Guid userId)
+    {
+        var requestUri = $"{PARTY}element-permissions?appId={appId}&userId={userId}";
+        return await _callerProvider.GetAsync<List<string>>(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<TeamDetailModel?> GetDetailAsync(Guid id)
     {
-        var requestUri = $"api/team/deatil";
+        var requestUri = $"{_party}detail";
         return await _callerProvider.GetAsync<object, TeamDetailModel>(requestUri, new { id });
     }
+
+    public async Task<List<TeamModel>> GetListAsync(Guid userId = default)
+    {
+        var requestUri = $"{_party}list";
+        if (Guid.Empty != userId)
+        {
+            requestUri = $"{requestUri}?userId={userId}";
+        }
+        return await _callerProvider.GetAsync<List<TeamModel>>(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<List<StaffModel>> GetListByTeamAsync(Guid teamId)
         var requestUri = $"api/staff/getListByTeam";
         return await _callerProvider.GetAsync<object, List<StaffModel>>(requestUri, new { id = teamId }) ?? new();
     }
+
+    public async Task<bool> ValidateCredentialsByAccountAsync(string account, string password)
+    {
+        var requestUri = $"api/user/validateByAccount";
+        return await _callerProvider.PostAsync<object, bool>(requestUri, new { account = account, password = password });
+    }
+
+    public async Task<UserModel> FindByAccountAsync(string account)
+    {
+        var requestUri = $"api/user/findByAccount";
+        return await _callerProvider.GetAsync<object, UserModel>(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<HttpEnvironmentDelegatingHandler>();
         });
     }
 
@@ -22,10 +23,14 @@ public static IServiceCollection AddAuthClient(this IServiceCollection services,
     {
         ArgumentNullException.ThrowIfNull(callerOptions, nameof(callerOptions));
 
+        services.AddHttpContextAccessor();
+        services.AddScoped<HttpEnvironmentDelegatingHandler>();
+        services.AddSingleton<IEnvironmentProvider, EnvironmentProvider>();
         services.AddCaller(callerOptions);
 
         services.AddScoped<IAuthClient>(serviceProvider =>
         {
+            Singleton<IServiceProvider>.Instance = serviceProvider;
             var callProvider = serviceProvider.GetRequiredService<ICallerFactory>().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 7f93352a4..3b7fe72e6 160000
--- a/src/BuildingBlocks/MASA.BuildingBlocks
+++ b/src/BuildingBlocks/MASA.BuildingBlocks
@@ -1 +1 @@
-Subproject commit 7f93352a4a42baf58cf97fd618957a63ff0e7a40
+Subproject commit 3b7fe72e67b2959a257f8976a2dbedf104bcf0a8
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<IAuthClient>();
+        }
+    }
+}
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..a53a3ee50
--- /dev/null
+++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs
@@ -0,0 +1,72 @@
+// Copyright (c) MASA Stack All rights reserved.
+// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
+
+using Masa.Contrib.BasicAbility.Auth.Infrastructure;
+using Microsoft.Extensions.Caching.Memory;
+
+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<MenuModel>();
+        var requestUri = $"api/permission/menus?appId={appId}&userId={userId}";
+        var callerProvider = new Mock<ICallerProvider>();
+        callerProvider.Setup(provider => provider.GetAsync<List<MenuModel>>(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<List<MenuModel>>(It.IsAny<string>(), default), Times.Once);
+        Assert.IsTrue(result is not null);
+    }
+
+    [TestMethod]
+    [DataRow("app-cache", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")]
+    public async Task TestGetMenusFromCacheAsync(string appId, string userId)
+    {
+        var data = new List<MenuModel>() {
+            new MenuModel{
+                Name ="Menu",
+                Code = "Code",
+                Icon="Icon",
+                Id = Guid.NewGuid()
+            }
+        };
+        var memoryCache = Singleton<IServiceProvider>.Instance.GetRequiredService<IMemoryCache>();
+        memoryCache.Set($"app:{appId}::user:{userId.ToLower()}", data);
+        var callerProvider = new Mock<ICallerProvider>();
+        var authClient = new AuthClient(callerProvider.Object);
+        var result = await authClient.PermissionService.GetMenusAsync(appId, Guid.Parse(userId));
+        Assert.IsTrue(result.Any());
+    }
+
+    [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<ICallerProvider>();
+        callerProvider.Setup(provider => provider.GetAsync<bool>(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<bool>(It.IsAny<string>(), default), Times.Once);
+    }
+
+    [TestMethod]
+    [DataRow("app1", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")]
+    public async Task TestGetElementPermissionsAsync(string appId, string userId)
+    {
+        var data = new List<string>();
+        var requestUri = $"api/permission/element-permissions?appId={appId}&userId={userId}";
+        var callerProvider = new Mock<ICallerProvider>();
+        callerProvider.Setup(provider => provider.GetAsync<List<string>>(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<List<string>>(It.IsAny<string>(), 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<ICallerProvider>();
         callerProvider.Setup(provider => provider.GetAsync<object, TeamDetailModel>(requestUri, It.IsAny<object>(), default)).ReturnsAsync(data).Verifiable();
         var authClient = new AuthClient(callerProvider.Object);
@@ -16,5 +19,18 @@ public async Task TestGetListAsync()
         callerProvider.Verify(provider => provider.GetAsync<object, TeamDetailModel>(requestUri, It.IsAny<object>(), default), Times.Once);
         Assert.IsTrue(result is not null);
     }
+
+    [TestMethod]
+    public async Task TestGetListAsync()
+    {
+        var data = new List<TeamModel>();
+        var requestUri = $"api/team/list";
+        var callerProvider = new Mock<ICallerProvider>();
+        callerProvider.Setup(provider => provider.GetAsync<List<TeamModel>>(requestUri, default)).ReturnsAsync(data).Verifiable();
+        var authClient = new AuthClient(callerProvider.Object);
+        var result = await authClient.TeamService.GetListAsync();
+        callerProvider.Verify(provider => provider.GetAsync<List<TeamModel>>(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<object, List<StaffModel>>(requestUri, It.IsAny<object>(), 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<ICallerProvider>();
+        callerProvider.Setup(provider => provider.PostAsync<object, bool>(requestUri, It.IsAny<object>(), default)).ReturnsAsync(data).Verifiable();
+        var authClient = new AuthClient(callerProvider.Object);
+        var result = await authClient.UserService.ValidateCredentialsByAccountAsync(account, password);
+        callerProvider.Verify(provider => provider.PostAsync<object, bool>(requestUri, It.IsAny<object>(), 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<ICallerProvider>();
+        callerProvider.Setup(provider => provider.GetAsync<object, UserModel>(requestUri, It.IsAny<object>(), default)).ReturnsAsync(data).Verifiable();
+        var authClient = new AuthClient(callerProvider.Object);
+        var result = await authClient.UserService.FindByAccountAsync(account);
+        callerProvider.Verify(provider => provider.GetAsync<object, UserModel>(requestUri, It.IsAny<object>(), default), Times.Once);
+        Assert.IsTrue(result is not null);
+    }
 }
 

From c8242c4e93a1b653044bf9994a0eae1531437f21 Mon Sep 17 00:00:00 2001
From: Mayue <mayue@lonsid.cn>
Date: Thu, 9 Jun 2022 10:41:19 +0800
Subject: [PATCH 2/2] chore:remove unnecessary unit test

---
 .../PermissionServiceTest.cs                  | 23 -------------------
 1 file changed, 23 deletions(-)

diff --git a/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs b/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs
index a53a3ee50..99e425748 100644
--- a/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs
+++ b/test/Masa.Contrib.BasicAbility.Auth.Tests/PermissionServiceTest.cs
@@ -1,9 +1,6 @@
 // Copyright (c) MASA Stack All rights reserved.
 // Licensed under the MIT License. See LICENSE.txt in the project root for license information.
 
-using Masa.Contrib.BasicAbility.Auth.Infrastructure;
-using Microsoft.Extensions.Caching.Memory;
-
 namespace Masa.Contrib.BasicAbility.Auth.Tests;
 
 [TestClass]
@@ -23,26 +20,6 @@ public async Task TestGetMenusAsync(string appId, string userId)
         Assert.IsTrue(result is not null);
     }
 
-    [TestMethod]
-    [DataRow("app-cache", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")]
-    public async Task TestGetMenusFromCacheAsync(string appId, string userId)
-    {
-        var data = new List<MenuModel>() {
-            new MenuModel{
-                Name ="Menu",
-                Code = "Code",
-                Icon="Icon",
-                Id = Guid.NewGuid()
-            }
-        };
-        var memoryCache = Singleton<IServiceProvider>.Instance.GetRequiredService<IMemoryCache>();
-        memoryCache.Set($"app:{appId}::user:{userId.ToLower()}", data);
-        var callerProvider = new Mock<ICallerProvider>();
-        var authClient = new AuthClient(callerProvider.Object);
-        var result = await authClient.PermissionService.GetMenusAsync(appId, Guid.Parse(userId));
-        Assert.IsTrue(result.Any());
-    }
-
     [TestMethod]
     [DataRow("app1", "code", "A9C8E0DD-1E9C-474D-8FE7-8BA9672D53D1")]
     public async Task TestAuthorizedAsync(string appId, string code, string userId)