From 56e4dcc11e7ff671dea761a8d6c7e68c3c9e6b1f Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Mon, 6 Feb 2023 16:44:25 -0500 Subject: [PATCH] fix #2578 - error notification sent via email includes direct link to specific log item, however redirect was causing an infinite loop. This resolves the problem and also preserves url querystring parameters during login/logout. --- Oqtane.Client/Modules/Admin/Login/Index.razor | 3 ++- Oqtane.Client/Modules/Admin/Logs/Index.razor | 17 +++++++++++------ .../Themes/Controls/Theme/LoginBase.cs | 16 ++++++++-------- Oqtane.Client/UI/SiteRouter.razor | 2 +- Oqtane.Server/Pages/Login.cshtml.cs | 5 +++++ Oqtane.Shared/Models/Route.cs | 6 ++++++ 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index d237190b..22fa249f 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -1,3 +1,4 @@ +@using System.Net @namespace Oqtane.Modules.Admin.Login @inherits ModuleBase @inject NavigationManager NavigationManager @@ -205,7 +206,7 @@ var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider .GetService(typeof(IdentityAuthenticationStateProvider)); authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true)); + NavigationManager.NavigateTo(NavigateUrl(WebUtility.UrlDecode(_returnUrl), true)); } else { diff --git a/Oqtane.Client/Modules/Admin/Logs/Index.razor b/Oqtane.Client/Modules/Admin/Logs/Index.razor index d763a5de..ed0c586c 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Index.razor @@ -106,12 +106,6 @@ else { try { - // external link to log item will display Details component - if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int id)) - { - NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, ModuleState.ModuleId, "Detail", $"/{id}")); - } - if (UrlParameters.ContainsKey("level")) { _level = UrlParameters["level"]; @@ -241,4 +235,15 @@ else _page = page; } + protected override void OnAfterRender(bool firstRender) + { + if (!firstRender) + { + // external link to log item will display Details component + if (PageState.QueryString.ContainsKey("id") && int.TryParse(PageState.QueryString["id"], out int id)) + { + NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, ModuleState.ModuleId, "Detail", $"/{id}")); + } + } + } } diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index 2e66f96c..9c0f2192 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -1,8 +1,10 @@ using System; +using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; using Oqtane.Enums; +using Oqtane.Models; using Oqtane.Providers; using Oqtane.Security; using Oqtane.Services; @@ -22,20 +24,18 @@ namespace Oqtane.Themes.Controls protected void LoginUser() { - var returnurl = PageState.Alias.Path; - if (PageState.Page.Path != "/") - { - returnurl += "/" + PageState.Page.Path; - } - NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + returnurl)); + Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); + NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery))); } protected async Task LogoutUser() { await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username); - // check if anonymous user can access page - var url = PageState.Alias.Path + "/" + PageState.Page.Path; + Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); + var url = route.PathAndQuery; + + // verify if anonymous users can access page if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.Permissions)) { url = PageState.Alias.Path; diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index f003bd49..9c7dedb9 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -250,7 +250,7 @@ if (user == null) { // redirect to login page if user not logged in as they may need to be authenticated - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath)); + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + WebUtility.UrlEncode(route.PathAndQuery))); } else { diff --git a/Oqtane.Server/Pages/Login.cshtml.cs b/Oqtane.Server/Pages/Login.cshtml.cs index 40202a16..7fa4bb87 100644 --- a/Oqtane.Server/Pages/Login.cshtml.cs +++ b/Oqtane.Server/Pages/Login.cshtml.cs @@ -1,3 +1,4 @@ +using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; @@ -43,6 +44,10 @@ namespace Oqtane.Pages { returnurl = ""; } + else + { + returnurl = WebUtility.UrlDecode(returnurl); + } if (!returnurl.StartsWith("/")) { returnurl = "/" + returnurl; diff --git a/Oqtane.Shared/Models/Route.cs b/Oqtane.Shared/Models/Route.cs index 9b4cc683..43385d8f 100644 --- a/Oqtane.Shared/Models/Route.cs +++ b/Oqtane.Shared/Models/Route.cs @@ -24,6 +24,7 @@ namespace Oqtane.Models Query = uri.Query; Fragment = uri.Fragment; AbsolutePath = uri.AbsolutePath; + PathAndQuery = uri.PathAndQuery; AliasPath = aliaspath; PagePath = AbsolutePath; ModuleId = ""; @@ -90,6 +91,11 @@ namespace Oqtane.Models /// public string AbsolutePath { get; set; } + /// + /// The absolute path for the route including the querystring + /// + public string PathAndQuery { get; set; } + /// /// An absolute path may contain an alias path ///