diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AuthenticatorAppController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AuthenticatorAppController.cs
index c81ffa8bfe3..156626050eb 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AuthenticatorAppController.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/AuthenticatorAppController.cs
@@ -103,7 +103,7 @@ public async Task Index(EnableAuthenticatorViewModel model)
await Notifier.SuccessAsync(H["Your authenticator app has been verified."]);
- return await RedirectToTwoFactorAsync(user);
+ return await RedirectToTwoFactorAsync(user,model.ReturnUrl);
}
public async Task Reset()
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/SmsAuthenticatorController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/SmsAuthenticatorController.cs
index c3b80673627..85dbc39e9f1 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/SmsAuthenticatorController.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/SmsAuthenticatorController.cs
@@ -140,10 +140,10 @@ public async Task IndexPost(RequestCodeSmsAuthenticatorViewModel
await SetPendingPhoneNumberAsync(phoneNumber, user.UserName);
- return RedirectToAction(nameof(ValidateCode));
+ return RedirectToAction(nameof(ValidateCode),new { model.ReturnUrl });
}
- public async Task ValidateCode()
+ public async Task ValidateCode(string returnUrl=null)
{
var user = await UserManager.GetUserAsync(User);
if (user == null)
@@ -159,7 +159,7 @@ public async Task ValidateCode()
return RedirectToAction(nameof(Index));
}
-
+ ViewData["ReturnUrl"] = returnUrl;
var model = new EnableSmsAuthenticatorViewModel
{
PhoneNumber = pendingPhoneNumber,
@@ -193,7 +193,7 @@ public async Task ValidateCode(EnableSmsAuthenticatorViewModel mo
await Notifier.SuccessAsync(H["Your phone number has been confirmed."]);
- return await RedirectToTwoFactorAsync(user);
+ return await RedirectToTwoFactorAsync(user,model.ReturnUrl);
}
await Notifier.ErrorAsync(H["Invalid verification code."]);
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationBaseController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationBaseController.cs
index d6774acbfdd..735698bd47e 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationBaseController.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationBaseController.cs
@@ -131,7 +131,7 @@ protected async Task RefreshTwoFactorClaimAsync(IUser user)
}
}
- protected async Task RedirectToTwoFactorAsync(IUser user)
+ protected async Task RedirectToTwoFactorAsync(IUser user, string returnUrl=null)
{
if (await UserManager.CountRecoveryCodesAsync(user) == 0)
{
@@ -142,12 +142,13 @@ protected async Task RedirectToTwoFactorAsync(IUser user)
await Notifier.WarningAsync(H["New recovery codes were generated."]);
- return RedirectToAction(nameof(TwoFactorAuthenticationController.ShowRecoveryCodes), _twoFactorAuthenticationControllerName);
+ // 传递 returnUrl 参数
+ return RedirectToAction(nameof(TwoFactorAuthenticationController.ShowRecoveryCodes), _twoFactorAuthenticationControllerName, new { returnUrl });
}
+ // 如果不需要生成新的恢复码,则直接重定向到 TwoFactorIndex
return RedirectToTwoFactorIndex();
}
-
protected async Task> GetTwoFactorProvidersAsync(IUser user)
{
var providers = await UserManager.GetValidTwoFactorProvidersAsync(user);
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationController.cs b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationController.cs
index 06ae865c89c..169c49bf356 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationController.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Controllers/TwoFactorAuthenticationController.cs
@@ -213,7 +213,7 @@ public async Task LoginWithRecoveryCode(LoginWithRecoveryCodeView
return View(model);
}
- public async Task Index()
+ public async Task Index(string returnUrl=null)
{
var user = await UserManager.GetUserAsync(User);
if (user == null)
@@ -223,18 +223,20 @@ public async Task Index()
var providers = await GetTwoFactorProvidersAsync(user);
var model = new TwoFactorAuthenticationViewModel();
- await PopulateModelAsync(user, providers, model);
+
+ await PopulateModelAsync(user, providers, model,returnUrl);
if (user is User u)
{
model.PreferredProvider = u.As().DefaultProvider;
}
-
+ ViewData["ReturnUrl"] = returnUrl;
+ //RedirectToLocal(returnUrl);
return View(model);
}
[HttpPost]
- public async Task Index(TwoFactorAuthenticationViewModel model)
+ public async Task Index(TwoFactorAuthenticationViewModel model, string returnUrl = null)
{
var user = await UserManager.GetUserAsync(User);
if (user == null)
@@ -257,14 +259,27 @@ public async Task Index(TwoFactorAuthenticationViewModel model)
await Notifier.SuccessAsync(H["Preferences were updated successfully."]);
- return RedirectToAction(nameof(Index));
+ // 优先使用提供的 returnUrl,如果没有提供则重定向到 Index
+ if (!string.IsNullOrEmpty(returnUrl) && Url.IsLocalUrl(returnUrl))
+ {
+ return Redirect(returnUrl);
+ }
+ else
+ {
+ return RedirectToAction(nameof(Index));
+ }
+ //return RedirectToAction(nameof(Index));
}
await Notifier.ErrorAsync(H["Unable to update preferences."]);
}
await PopulateModelAsync(user, providers, model);
-
+ // 如果有 returnUrl,将其传递给视图
+ if (!string.IsNullOrEmpty(returnUrl))
+ {
+ ViewData["ReturnUrl"] = returnUrl;
+ }
return View(model);
}
@@ -328,7 +343,7 @@ public async Task GenerateRecoveryCodesPost()
return RedirectToAction(nameof(ShowRecoveryCodes));
}
- public async Task ShowRecoveryCodes()
+ public async Task ShowRecoveryCodes(string returnUrl=null)
{
var user = await UserManager.GetUserAsync(User);
if (user == null)
@@ -339,7 +354,10 @@ public async Task ShowRecoveryCodes()
var userId = await UserManager.GetUserIdAsync(user);
var recoveryCodes = await GetCachedRecoveryCodesAsync(userId);
-
+ if(Url.IsLocalUrl(returnUrl))
+ {
+ return Redirect(returnUrl);
+ }
if (recoveryCodes == null || recoveryCodes.Length == 0)
{
return RedirectToAction(nameof(Index));
@@ -474,7 +492,7 @@ private static string GetProvider(IList providers, IUser user, string pr
return defaultProvider;
}
- private async Task PopulateModelAsync(IUser user, IList providers, TwoFactorAuthenticationViewModel model)
+ private async Task PopulateModelAsync(IUser user, IList providers, TwoFactorAuthenticationViewModel model,string returnUrl="")
{
model.User = user;
model.IsTwoFaEnabled = await UserManager.GetTwoFactorEnabledAsync(user);
@@ -489,6 +507,7 @@ private async Task PopulateModelAsync(IUser user, IList providers, TwoFa
{
Provider = key,
IsEnabled = providers.Contains(key),
+ ReturnUrl = returnUrl
};
var shape = await _twoFactorDisplayManager.BuildDisplayAsync(method, this, "SummaryAdmin");
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/TwoFactorMethodDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/TwoFactorMethodDisplayDriver.cs
index 27916138379..a93faf1b109 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/TwoFactorMethodDisplayDriver.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/TwoFactorMethodDisplayDriver.cs
@@ -12,23 +12,27 @@ public override IDisplayResult Display(TwoFactorMethod model, BuildDisplayContex
{
return null;
}
-
+ // 从上下文中获取 returnUrl 参数
+
var icon = Initialize($"TwoFactorMethod_{model.Provider}_Icon", vm =>
{
vm.Provider = model.Provider;
vm.IsEnabled = model.IsEnabled;
+ vm.ReturnUrl = model.ReturnUrl; // 传递 returnUrl 参数
}).Location("SummaryAdmin", "Icon");
var content = Initialize($"TwoFactorMethod_{model.Provider}_Content", vm =>
{
vm.Provider = model.Provider;
vm.IsEnabled = model.IsEnabled;
+ vm.ReturnUrl = model.ReturnUrl; // 传递 returnUrl 参数
}).Location("SummaryAdmin", "Content");
var actions = Initialize($"TwoFactorMethod_{model.Provider}_Actions", vm =>
{
vm.Provider = model.Provider;
vm.IsEnabled = model.IsEnabled;
+ vm.ReturnUrl = model.ReturnUrl; // 传递 returnUrl 参数
}).Location("SummaryAdmin", "Actions");
return Combine(icon, content, actions);
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/UserDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/UserDisplayDriver.cs
index ad0064b3699..ffb7381fd63 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Drivers/UserDisplayDriver.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Drivers/UserDisplayDriver.cs
@@ -53,8 +53,7 @@ public override Task DisplayAsync(User user, BuildDisplayContext
return CombineAsync(
Initialize("UserFields", model => model.User = user).Location("SummaryAdmin", "Header:1"),
Initialize("UserInfo", model => model.User = user).Location("DetailAdmin", "Content:5"),
- Initialize("UserButtons", model => model.User = user).Location("SummaryAdmin", "Actions:1"),
- Initialize("UserActionsMenu", model => model.User = user).Location("SummaryAdmin", "ActionsMenu:5")
+ Initialize("UserButtons", model => model.User = user).Location("SummaryAdmin", "Actions:1")
);
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Extensions/ControllerExtensions.cs b/src/OrchardCore.Modules/OrchardCore.Users/Extensions/ControllerExtensions.cs
index 6b368864bfc..c97ae90868c 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Extensions/ControllerExtensions.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Extensions/ControllerExtensions.cs
@@ -106,7 +106,7 @@ internal static async Task SendEmailConfirmationTokenAsync(this Controll
},
protocol: controller.HttpContext.Request.Scheme);
- await SendEmailAsync(controller, user.Email, subject, new ConfirmEmailViewModel
+ await SendEmailAsync(controller, user.Email, subject, new ConfirmEmailViewModel()
{
User = user,
ConfirmEmailUrl = callbackUrl,
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Filters/TwoFactorAuthenticationAuthorizationFilter.cs b/src/OrchardCore.Modules/OrchardCore.Users/Filters/TwoFactorAuthenticationAuthorizationFilter.cs
index c0543341d0a..9991acd89be 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Filters/TwoFactorAuthenticationAuthorizationFilter.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Filters/TwoFactorAuthenticationAuthorizationFilter.cs
@@ -1,3 +1,4 @@
+using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
@@ -31,7 +32,56 @@ public TwoFactorAuthenticationAuthorizationFilter(
_userManager = userManager;
_twoFactorHandlerCoordinator = twoFactorHandlerCoordinator;
}
+ public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+ {
+ ArgumentNullException.ThrowIfNull(context);
+
+ if (context.HttpContext?.User?.Identity?.IsAuthenticated == false ||
+ context.HttpContext.Request.Path.Equals("/" + _userOptions.LogoffPath, StringComparison.OrdinalIgnoreCase) ||
+ context.HttpContext.Request.Path.Equals("/" + _userOptions.TwoFactorAuthenticationPath, StringComparison.OrdinalIgnoreCase) ||
+ context.HttpContext.Request.Path.Equals("/TwoFactor-Authenticator/", StringComparison.OrdinalIgnoreCase))
+ {
+ await next();
+ return;
+ }
+
+ var routeValues = context.HttpContext.Request.RouteValues;
+ var areaName = routeValues["area"]?.ToString();
+
+ if (areaName != null && string.Equals(areaName, UserConstants.Features.Users, StringComparison.OrdinalIgnoreCase))
+ {
+ var controllerName = routeValues["controller"]?.ToString();
+ if (controllerName != null && _allowedControllerNames.Contains(controllerName, StringComparer.OrdinalIgnoreCase))
+ {
+ await next();
+ return;
+ }
+ }
+
+ if (context.HttpContext.User.HasClaim(claim => claim.Type == UserConstants.TwoFactorAuthenticationClaimType))
+ {
+ var user = await _userManager.GetUserAsync(context.HttpContext.User);
+
+ if (user == null)
+ {
+ await next();
+ return;
+ }
+
+ if (await _twoFactorHandlerCoordinator.IsRequiredAsync(user))
+ {
+ // 获取当前请求的 URL
+ var originalUrl = context.HttpContext.Request.GetEncodedUrl();
+ // 构建带有 returnUrl 参数的重定向 URL
+ var redirectUrl = $"/{_userOptions.TwoFactorAuthenticationPath}?returnUrl={Uri.EscapeDataString(originalUrl)}";
+ context.Result = new RedirectResult(redirectUrl);
+ return;
+ }
+ }
+
+ await next();
+ }
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
ArgumentNullException.ThrowIfNull(context);
@@ -68,7 +118,26 @@ public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
if (await _twoFactorHandlerCoordinator.IsRequiredAsync(user))
{
- context.Result = new RedirectResult("~/" + _userOptions.TwoFactorAuthenticationPath);
+ // 获取当前访问的URL
+ var currentUrl = context.HttpContext.Request.GetEncodedUrl();
+ var requestScheme = context.HttpContext.Request.Scheme;
+ var host = context.HttpContext.Request.Host;
+// var currentUrl = $"{requestScheme}://{host}{context.HttpContext.Request.PathBase}{context.HttpContext.Request.Path}{context.HttpContext.Request.QueryString}";
+
+// var returnUrl = currentUrl.StartsWith($"{requestScheme}://{host}")
+// ? $"{context.HttpContext.Request.PathBase}{context.HttpContext.Request.Path}{context.HttpContext.Request.QueryString}"
+// : currentUrl;
+ // 如果是同域名,只保留路径部分
+ var returnUrl = currentUrl.StartsWith($"{requestScheme}://{host}")
+ ? $"{context.HttpContext.Request.Path}{context.HttpContext.Request.QueryString}"
+ : currentUrl;
+
+ // 生成重定向URL
+ var redirectUrl = $"/{_userOptions.TwoFactorAuthenticationPath}?returnUrl={Uri.EscapeDataString(returnUrl)}";
+
+ context.Result = new RedirectResult(redirectUrl);
+
+ // context.Result = new RedirectResult("~/" + _userOptions.TwoFactorAuthenticationPath);
}
}
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Liquid/UserFilters.cs b/src/OrchardCore.Modules/OrchardCore.Users/Liquid/UserFilters.cs
index b8ce03755cd..1e1d36564e9 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Liquid/UserFilters.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Liquid/UserFilters.cs
@@ -3,7 +3,6 @@
using Fluid.Values;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
using OrchardCore.Liquid;
using OrchardCore.Security;
using OrchardCore.Security.Permissions;
@@ -47,10 +46,6 @@ public static ValueTask HasClaim(FluidValue input, FilterArguments a
if (string.Equals(claimType, Permission.ClaimType, StringComparison.OrdinalIgnoreCase) &&
user.HasClaim(StandardClaims.SiteOwner.Type, StandardClaims.SiteOwner.Value))
{
- var logger = context.Services.GetRequiredService>();
-
- logger.LogWarning("The tenant is using the 'has_claim' Liquid filter for Permission claims '{ClaimName}', which will break in the next major release of OrchardCore; please use 'has_permission: \"{ClaimName}\"' instead.", claimName, claimName);
-
return BooleanValue.True;
}
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Models/TwoFactorMethod.cs b/src/OrchardCore.Modules/OrchardCore.Users/Models/TwoFactorMethod.cs
index 842b3aa0e0c..d5cccbcd20c 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Models/TwoFactorMethod.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Models/TwoFactorMethod.cs
@@ -5,4 +5,5 @@ public class TwoFactorMethod
public string Provider { get; set; }
public bool IsEnabled { get; set; }
+ public string ReturnUrl { get; set; }
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs
index 92446e5da87..deb4b9e969a 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Startup.cs
@@ -424,7 +424,6 @@ public override void ConfigureServices(IServiceCollection services)
o.MemberAccessStrategy.Register();
});
- services.AddScoped, UserRegistrationAdminDisplayDriver>();
services.AddSiteDisplayDriver();
services.AddNavigationProvider();
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/TwoFactorAuthenticationStartup.cs b/src/OrchardCore.Modules/OrchardCore.Users/TwoFactorAuthenticationStartup.cs
index 5d17b78f2d8..20629391bb6 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/TwoFactorAuthenticationStartup.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/TwoFactorAuthenticationStartup.cs
@@ -7,7 +7,6 @@
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.Modules;
using OrchardCore.Mvc.Core.Utilities;
-using OrchardCore.Security.Permissions;
using OrchardCore.Users.Controllers;
using OrchardCore.Users.Drivers;
using OrchardCore.Users.Endpoints.EmailAuthenticator;
@@ -33,12 +32,10 @@ public override void ConfigureServices(IServiceCollection services)
options.Filters.Add();
});
- services.AddScoped, UserTwoFactorDisplayDriver>();
services.AddScoped();
services.AddScoped, TwoFactorUserMenuDisplayDriver>();
services.AddSiteDisplayDriver();
services.AddScoped, TwoFactorMethodDisplayDriver>();
- services.AddPermissionProvider();
}
public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/EnableSmsAuthenticatorViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/EnableSmsAuthenticatorViewModel.cs
index 1956b3959b9..6657d67b181 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/EnableSmsAuthenticatorViewModel.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/EnableSmsAuthenticatorViewModel.cs
@@ -8,4 +8,5 @@ public class EnableSmsAuthenticatorViewModel
public string Code { get; set; }
public string PhoneNumber { get; set; }
+ public string ReturnUrl { get; set; }
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/RequestCodeSmsAuthenticatorViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/RequestCodeSmsAuthenticatorViewModel.cs
index 5931f81695d..f21c3758ad1 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/RequestCodeSmsAuthenticatorViewModel.cs
+++ b/src/OrchardCore.Modules/OrchardCore.Users/ViewModels/RequestCodeSmsAuthenticatorViewModel.cs
@@ -8,4 +8,5 @@ public class RequestCodeSmsAuthenticatorViewModel
[BindNever]
public bool AllowChangingPhoneNumber { get; set; }
+ public string ReturnUrl { get; set; }
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/Items/TwoFactorMethod.Authenticator.Actions.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/Items/TwoFactorMethod.Authenticator.Actions.cshtml
index c84c6e2c49a..ab10148c778 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/Items/TwoFactorMethod.Authenticator.Actions.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/Items/TwoFactorMethod.Authenticator.Actions.cshtml
@@ -4,10 +4,10 @@
@if (Model.IsEnabled)
{
- @T["Set"]
+ @T["Set"]
@T["Reset"]
}
else
{
- @T["Add"]
+ @T["Add"]
}
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticator/ValidateCode.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticator/ValidateCode.cshtml
index 69fded480f6..feb0601f590 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticator/ValidateCode.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticator/ValidateCode.cshtml
@@ -20,12 +20,13 @@
-
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticatorValidation.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticatorValidation.cshtml
index ea3faad2903..7ca4e83919f 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticatorValidation.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/SmsAuthenticatorValidation.cshtml
@@ -4,7 +4,7 @@
@T["Please click here to receive a one-time verification code via SMS."]
-
+SmsAuthenticatorValidation
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/TemplateUserConfirmEmail.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/TemplateUserConfirmEmail.cshtml
index 891c422f467..dbad46ccb69 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/TemplateUserConfirmEmail.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/TemplateUserConfirmEmail.cshtml
@@ -13,7 +13,7 @@
@T["Dear {0},", Model.User.UserName]
-@T["Please click here to confirm your account.", Html.Raw(Model.ConfirmEmailUrl)]
+@T["Please click here to confirm your account.", Model.ConfirmEmailUrl]
@T.Plural(totalMinutes, "Please be aware that this link will expire in {0} minute.", "Please be aware that this link will expire in {0} minutes.", totalMinutes)
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/TwoFactorAuthentication/Index.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/TwoFactorAuthentication/Index.cshtml
index 05f5d5bb50b..c3ae1eb8b07 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/TwoFactorAuthentication/Index.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/TwoFactorAuthentication/Index.cshtml
@@ -11,7 +11,7 @@
ViewLayout = "Layout__TwoFactor";
}
-
+TowFactorAuthentication
@if (Model.AuthenticationMethods.Count == 0)
{
@@ -59,7 +59,7 @@
}
else if (!Model.IsTwoFaEnabled && Model.ValidTwoFactorProviders.Count > 0)
{
-
}
@@ -99,7 +99,7 @@
{
@T["The current device has been saved during the two-factor authentication process."]
-
@@ -108,7 +108,7 @@
@if (Model.ValidTwoFactorProviders.Count > 1)
{
-
diff --git a/src/OrchardCore.Modules/OrchardCore.Users/Views/UserButtons.cshtml b/src/OrchardCore.Modules/OrchardCore.Users/Views/UserButtons.cshtml
index 877d1354f35..5401fff36df 100644
--- a/src/OrchardCore.Modules/OrchardCore.Users/Views/UserButtons.cshtml
+++ b/src/OrchardCore.Modules/OrchardCore.Users/Views/UserButtons.cshtml
@@ -1,12 +1,17 @@
@model SummaryAdminUserViewModel
-
+@using OrchardCore.Entities
+@using OrchardCore.Users.Models
+@using Microsoft.AspNetCore.Identity
+@using OrchardCore.Users
+@inject UserManager UserManager
@inject IAuthorizationService AuthorizationService
-
@{
var isCurrentUser = Model.User.UserName == User.Identity.Name;
+ var canEdit = await AuthorizationService.AuthorizeAsync(User, CommonPermissions.EditUsers, Model.User);
+ var isLockedOut = await UserManager.IsLockedOutAsync(Model.User);
}
-@if (await AuthorizationService.AuthorizeAsync(User, CommonPermissions.EditUsers, Model.User))
+@if (canEdit)
{
@T["Edit"]
}
@@ -15,3 +20,25 @@
{
@T["View"]
}
+
+@if (canEdit)
+{
+ @T["Edit Password"]
+ if (isLockedOut)
+ {
+ @T["Unlock"]
+ }
+}
+
+@if (!isCurrentUser && await AuthorizationService.AuthorizeAsync(User, CommonPermissions.DeleteUsers, Model.User))
+{
+ @T["Delete"]
+}
+
+@if (canEdit && !Model.User.EmailConfirmed && Site.As().UsersMustValidateEmail)
+{
+
+}