From af90dabefecab3124e4b9d76007788ec4717820b Mon Sep 17 00:00:00 2001 From: wzh425 Date: Wed, 13 Mar 2024 11:14:23 +0800 Subject: [PATCH] feat: ImpersonatedNavigation --- .../Masa.Auth.Contracts.Admin.csproj | 4 +- .../Masa.Auth.Security.OAuth.Providers.csproj | 2 +- .../Subjects/ImpersonatedNavigation.razor | 127 ++++++++++ .../Subjects/ImpersonatedNavigation.razor.cs | 223 ++++++++++++++++++ .../Pages/Subjects/Users/User.razor | 96 ++++---- .../Validations/ImpersonationCacheItem.cs | 32 --- .../Masa.Auth.Web.Sso.csproj | 2 +- 7 files changed, 404 insertions(+), 82 deletions(-) create mode 100644 src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor create mode 100644 src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor.cs delete mode 100644 src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/ImpersonationCacheItem.cs diff --git a/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj b/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj index 700dad09c..98a488eb1 100644 --- a/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj +++ b/src/Contracts/Masa.Auth.Contracts.Admin/Masa.Auth.Contracts.Admin.csproj @@ -12,12 +12,12 @@ - + - + diff --git a/src/Web/Masa.Auth.Security.OAuth.Providers/Masa.Auth.Security.OAuth.Providers.csproj b/src/Web/Masa.Auth.Security.OAuth.Providers/Masa.Auth.Security.OAuth.Providers.csproj index c32f9f9b5..82841f0cf 100644 --- a/src/Web/Masa.Auth.Security.OAuth.Providers/Masa.Auth.Security.OAuth.Providers.csproj +++ b/src/Web/Masa.Auth.Security.OAuth.Providers/Masa.Auth.Security.OAuth.Providers.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor new file mode 100644 index 000000000..a3f02da6d --- /dev/null +++ b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor @@ -0,0 +1,127 @@ +@using Masa.BuildingBlocks.StackSdks.Auth; +@using Masa.BuildingBlocks.StackSdks.Pm; +@using Microsoft.AspNetCore.Hosting; +@inherits AdminCompontentBase +@inject IMultiEnvironmentUserContext MultiEnvironmentUserContext +@inject IWebHostEnvironment WebHostEnvironment +@inject IMasaStackConfig MasaStackConfig +@inject IPmClient PmClient +@inject IAuthClient AuthClient + + + + @ActivatorContent?.Invoke(context) + + + + + + + + + +@code { + +} diff --git a/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor.cs b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor.cs new file mode 100644 index 000000000..5f8dd697a --- /dev/null +++ b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Component/Subjects/ImpersonatedNavigation.razor.cs @@ -0,0 +1,223 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the Apache License. See LICENSE.txt in the project root for license information. + +namespace Masa.Auth.Web.Admin.Rcl.Pages.Component.Subjects; + +public partial class ImpersonatedNavigation : AdminCompontentBase +{ + private const string MENU_URL_NAME = "url"; + + [Parameter] + public Guid UserId { get; set; } + + [Parameter] + public RenderFragment ActivatorContent { get; set; } = null!; + + [Parameter] + public Func? OnFavoriteAdd { get; set; } + + [Parameter] + public Func? OnFavoriteRemove { get; set; } + + bool _visible; + private List<(string name, string url)>? _recentVisits; + private List>? _recommendApps; + private List _favorites = new(); + ExpansionMenu? _menu; + string impersonationToken = string.Empty; + + private async Task GetMenuAndFavorites() + { + _menu = await GenerateMenuAsync(); + _favorites = _menu.GetMenusByStates(ExpansionMenuState.Favorite) ?? new(); + StateHasChanged(); + } + + private async Task GetRecommendApps() + { + //TODO pm config + var recommendAppIdentities = new List() + { + MasaStackConfig.GetWebId(MasaStackProject.PM), MasaStackConfig.GetWebId(MasaStackProject.DCC), + MasaStackConfig.GetWebId(MasaStackProject.Auth) + }; + var environment = MultiEnvironmentUserContext.Environment; + if (environment.IsNullOrEmpty()) + { + environment = WebHostEnvironment.EnvironmentName; + } + + var projects = await PmClient.ProjectService.GetProjectAppsAsync(environment); + _recommendApps = projects.SelectMany(p => p.Apps).Where(a => recommendAppIdentities.Contains(a.Identity)) + .Select(a => new KeyValuePair(a.Name, a.Url)).ToList(); + + StateHasChanged(); + } + + private async Task GetImpersonationToken() + { + var impersonate = await AuthClient.UserService.ImpersonateAsync(UserId); + if (impersonate != null) + { + impersonationToken = impersonate.ImpersonationToken; + } + } + + private void VisibleChanged(bool visible) + { + if (visible && _menu == null) + { + _ = GetRecommendApps(); + _ = GetRecentVisits(); + _ = GetMenuAndFavorites(); + } + + if (visible && string.IsNullOrEmpty(impersonationToken)) + { + _ = GetImpersonationToken(); + } + + _visible = visible; + } + + private void SearchChanged(string? search) + { + _menu?.SetHiddenBySearch(search, TranslateProvider); + } + + private void MenuItemClickAsync(ExpansionMenu menu) + { + var url = menu.GetData(MENU_URL_NAME); + if (string.IsNullOrWhiteSpace(url)) + { + return; + } + + NavigateTo(url); + } + + private async Task MenuItemOperClickAsync(ExpansionMenu menu) + { + if (menu.State == ExpansionMenuState.Normal) + { + await FavoriteRemoveAsync(menu); + } + else if (menu.State == ExpansionMenuState.Favorite) + { + await FavoriteAddAsync(menu); + } + } + + private async Task GenerateMenuAsync() + { + var menu = ExpansionMenu.CreateRootMenu(ExpansionMenuSituation.Favorite); + try + { + var apps = (await AuthClient.ProjectService.GetGlobalNavigations()).SelectMany(p => p.Apps).ToList(); + var categories = apps.GroupBy(a => a.Tag).ToList(); + var favorites = await FetchFavorites(); + + foreach (var category in categories) + { + var categoryMenu = new ExpansionMenu(category.Key, category.Key, ExpansionMenuType.Category, ExpansionMenuState.Normal, menu.MetaData, + parent: menu); + foreach (var app in category.Where(a => a.Navs.Any())) + { + var appMenu = new ExpansionMenu(app.Id.ToString(), app.Name, ExpansionMenuType.App, ExpansionMenuState.Normal, menu.MetaData, + parent: categoryMenu); + foreach (var nav in app.Navs) + { + appMenu.AddChild(ConvertForNav(nav, appMenu.Deep + 1, appMenu, favorites)); + } + + categoryMenu.AddChild(appMenu); + } + + menu.AddChild(categoryMenu); + } + } + catch + { + } + + return menu; + } + + private ExpansionMenu ConvertForNav(NavModel navModel, int deep, ExpansionMenu parent, List favorites) + { + var state = favorites.Any(favorite => favorite == navModel.Code) ? ExpansionMenuState.Favorite : ExpansionMenuState.Normal; + var menu = new ExpansionMenu(navModel.Code, navModel.Name, ExpansionMenuType.Nav, state, parent.MetaData, parent: parent) + .AddData(MENU_URL_NAME, navModel.Url); + foreach (var childrenNav in navModel.Children) + { + menu.AddChild(ConvertForNav(childrenNav, deep++, menu, favorites)); + } + + menu.Disabled = menu.Children.Count > 0; + return menu; + } + + private async Task> FetchFavorites() + { + return (await AuthClient.PermissionService.GetFavoriteMenuListAsync()) + .Select(m => m.Value.ToString()).ToList(); + } + + private async Task GetRecentVisits() + { + var visitedList = await AuthClient.UserService.GetVisitedListAsync(); + _recentVisits = visitedList.Select(v => new ValueTuple(v.Name, v.Url)).ToList(); + + StateHasChanged(); + } + + private void NavigateTo(string? url) + { + if (url is null) + { + return; + } + + if (url.IndexOf("http") > -1) + { + UriBuilder uriBuilder = new UriBuilder(url); + uriBuilder.Query = $"impersonationToken={impersonationToken}"; + url = uriBuilder.Uri.ToString(); + } + NavigationManager.NavigateTo(url, forceLoad: true); + } + + private async Task FavoriteRemoveAsync(ExpansionMenu nav) + { + var favoriteNav = _favorites.FirstOrDefault(e => e.Id == nav.Id); + if (favoriteNav == null) + { + return; + } + + _favorites.Remove(favoriteNav); + if (OnFavoriteRemove != null) + { + await OnFavoriteRemove.Invoke(favoriteNav.Id); + } + } + + private async Task FavoriteAddAsync(ExpansionMenu nav) + { + if (_favorites.Any(e => e.Id == nav.Id)) + { + return; + } + + _favorites.Add(nav); + if (OnFavoriteAdd != null) + { + await OnFavoriteAdd.Invoke(nav.Id); + } + } + + private async Task OnOutsideClick() + { + var a = 1; + } +} diff --git a/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Subjects/Users/User.razor b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Subjects/Users/User.razor index 168bcbf87..4251b8b1f 100644 --- a/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Subjects/Users/User.razor +++ b/src/Web/Masa.Auth.Web.Admin.Rcl/Pages/Subjects/Users/User.razor @@ -2,45 +2,45 @@ @inherits AdminCompontentBase - -
- -
- -
-
- - @(Filter is true ? IconConstants.FilterOff : IconConstants.Filter) + +
+ +
+ +
+
+ + @(Filter is true ? IconConstants.FilterOff : IconConstants.Filter)
- @IconConstants.Add - @T("Add") - -
-
- - - - - - -
-
- - - - @header.Text - - - @switch (context.Header.Value) + @IconConstants.Add + @T("Add") + +
+
+ + + + + + +
+ + + + + @header.Text + + + @switch (context.Header.Value) { case nameof(UserDto.Avatar):
@@ -65,18 +65,22 @@ case "Action":
- @IconConstants.Update - - - @IconConstants.Authorize - - - @IconConstants.Claim - + @IconConstants.Update + + + @IconConstants.Authorize + - mdi-login-variant + @IconConstants.Claim -
+ + + + mdi-login-variant + + + +
break; default: diff --git a/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/ImpersonationCacheItem.cs b/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/ImpersonationCacheItem.cs deleted file mode 100644 index 8aa97d0ff..000000000 --- a/src/Web/Masa.Auth.Web.Sso/Infrastructure/Validations/ImpersonationCacheItem.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) MASA Stack All rights reserved. -// Licensed under the Apache License. See LICENSE.txt in the project root for license information. - -namespace Masa.Auth.Web.Sso.Infrastructure.Validations; - -[Serializable] -public class ImpersonationCacheItem -{ - public const string CACHE_NAME = "AppImpersonationCache"; - - public int? ImpersonatorTenantId { get; set; } - - public long ImpersonatorUserId { get; set; } - - public int? TargetTenantId { get; set; } - - public long TargetUserId { get; set; } - - public bool IsBackToImpersonator { get; set; } - - public ImpersonationCacheItem() - { - - } - - public ImpersonationCacheItem(int? targetTenantId, long targetUserId, bool isBackToImpersonator) - { - TargetTenantId = targetTenantId; - TargetUserId = targetUserId; - IsBackToImpersonator = isBackToImpersonator; - } -} \ No newline at end of file diff --git a/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj b/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj index 39fc31c38..61829bad0 100644 --- a/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj +++ b/src/Web/Masa.Auth.Web.Sso/Masa.Auth.Web.Sso.csproj @@ -24,7 +24,7 @@ - +