KeyPressed(e))">
- @if (_allowexternallogin)
- {
-
-
- }
- @if (_allowsitelogin)
- {
-
-
-
-
-
-
-
-
-
-
-
- @if (!_alwaysremember)
+
}
@code {
- private bool _allowsitelogin = true;
+ private string _action = "Login";
private bool _allowexternallogin = false;
+ private bool _allowsitelogin = true;
+ private bool _allowloginlink = false;
private bool _allowpasskeys = false;
+
private ElementReference login;
private bool validated = false;
- private bool twofactor = false;
private string _username = string.Empty;
private ElementReference username;
private string _password = string.Empty;
private string _passwordtype = "password";
private string _togglepassword = string.Empty;
+ private ElementReference password;
private bool _remember = false;
private bool _alwaysremember = false;
- private string _code = string.Empty;
private string _registerurl = string.Empty;
+ private string _email = string.Empty;
+ private string _code = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous;
public override bool? Prerender => true;
@@ -116,6 +156,7 @@ else
{
_allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false;
_allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true"));
+ _allowloginlink = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:LoginLink", "false"));
_allowpasskeys = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:Passkeys", "false"));
_alwaysremember = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AlwaysRemember", "false"));
@@ -186,6 +227,48 @@ else
}
}
+ private async Task KeyPressed(KeyboardEventArgs e)
+ {
+ if (e.Code == "Enter" || e.Code == "NumpadEnter")
+ {
+ switch (_action)
+ {
+ case "Login":
+ await Login();
+ break;
+ }
+ }
+ }
+
+ private void SetAction(string action)
+ {
+ _action = action;
+ _username = "";
+ _password = "";
+ _email = "";
+ ClearModuleMessage();
+ StateHasChanged();
+ }
+
+ private void ExternalLogin()
+ {
+ NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + WebUtility.UrlEncode(PageState.ReturnUrl)), true);
+ }
+
+ private void TogglePassword()
+ {
+ if (_passwordtype == "password")
+ {
+ _passwordtype = "text";
+ _togglepassword = SharedLocalizer["HidePassword"];
+ }
+ else
+ {
+ _passwordtype = "password";
+ _togglepassword = SharedLocalizer["ShowPassword"];
+ }
+ }
+
private async Task Login()
{
try
@@ -197,7 +280,7 @@ else
var hybrid = (PageState.Runtime == Shared.Runtime.Hybrid);
var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password, LastIPAddress = SiteState.RemoteIPAddress};
- if (!twofactor)
+ if (_action == "Login")
{
_remember = _alwaysremember || _remember;
user = await UserService.LoginUserAsync(user, hybrid, _remember);
@@ -233,13 +316,13 @@ else
{
if (SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:TwoFactor", "false") == "required" || (user != null && user.TwoFactorRequired))
{
- twofactor = true;
+ _action = "TwoFactor";
validated = false;
AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info);
}
else
{
- if (!twofactor)
+ if (_action != "TwoFactor")
{
await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username);
AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error);
@@ -264,23 +347,30 @@ else
}
}
- private void Cancel()
+ private void CancelLogin()
{
NavigationManager.NavigateTo(PageState.ReturnUrl);
}
- private async Task Forgot()
+ private async Task PasskeyLogin()
+ {
+ // post back to the Passkey page so that the cookies are set correctly
+ var interop = new Interop(JSRuntime);
+ var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, operation = "request", returnurl = NavigateUrl() };
+ string url = Utilities.TenantUrl(PageState.Alias, "/pages/passkey/");
+ await interop.SubmitForm(url, fields);
+ }
+
+ private async Task ForgotPassword()
{
try
{
- if (_username != string.Empty)
+ if (!string.IsNullOrEmpty(_username))
{
- var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId);
- if (user != null)
+ if (await UserService.ForgotPasswordAsync(_username))
{
- await UserService.ForgotPasswordAsync(user);
await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username);
- AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info);
+ AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
}
else
{
@@ -289,10 +379,8 @@ else
}
else
{
- AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info);
+ AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
}
-
- StateHasChanged();
}
catch (Exception ex)
{
@@ -301,51 +389,62 @@ else
}
}
- private void Reset()
+ private async Task ForgotUsername()
{
- twofactor = false;
- _username = "";
- _password = "";
- ClearModuleMessage();
- StateHasChanged();
- }
-
- private async Task KeyPressed(KeyboardEventArgs e)
- {
- if (e.Code == "Enter" || e.Code == "NumpadEnter")
+ try
{
- await Login();
+ if (!string.IsNullOrEmpty(_email))
+ {
+ if (await UserService.ForgotUsernameAsync(_email))
+ {
+ AddModuleMessage(Localizer["Message.ForgotUsername"], MessageType.Info);
+ await logger.LogInformation(LogFunction.Security, "Username Reminder Notification Sent For Email {Email}", _email);
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
+ }
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
+ }
+ }
+ catch (Exception ex)
+ {
+ await logger.LogError(ex, "Error Sending Username Reminder {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.ForgotUsername"], MessageType.Error);
}
}
- private void TogglePassword()
+ private async Task LoginLink()
{
- if (_passwordtype == "password")
+ try
{
- _passwordtype = "text";
- _togglepassword = SharedLocalizer["HidePassword"];
+ if (!string.IsNullOrEmpty(_email))
+ {
+ if (await UserService.SendLoginLinkAsync(_email))
+ {
+ AddModuleMessage(Localizer["Message.SendLoginLink"], MessageType.Info);
+ await logger.LogInformation(LogFunction.Security, "Login Link Sent To Email {Email}", _email);
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning);
+ }
+ }
+ else
+ {
+ AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning);
+ }
}
- else
+ catch (Exception ex)
{
- _passwordtype = "password";
- _togglepassword = SharedLocalizer["ShowPassword"];
+ await logger.LogError(ex, "Error Sending Login Link {Error}", ex.Message);
+ AddModuleMessage(Localizer["Error.SendLoginLink"], MessageType.Error);
}
}
- private void ExternalLogin()
- {
- NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + WebUtility.UrlEncode(PageState.ReturnUrl)), true);
- }
-
- private async Task Passkey()
- {
- // post back to the Passkey page so that the cookies are set correctly
- var interop = new Interop(JSRuntime);
- var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, operation = "request", returnurl = NavigateUrl() };
- string url = Utilities.TenantUrl(PageState.Alias, "/pages/passkey/");
- await interop.SubmitForm(url, fields);
- }
-
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && PageState.QueryString.ContainsKey("options"))
@@ -377,11 +476,21 @@ else
return;
}
- if (firstRender && PageState.User == null && _allowsitelogin)
+ if (firstRender && PageState.User == null && _allowsitelogin && _action == "Login")
{
- if (!string.IsNullOrEmpty(username.Id)) // ensure username is visible in UI
+ if (string.IsNullOrEmpty(_username))
{
- await username.FocusAsync();
+ if (!string.IsNullOrEmpty(username.Id)) // ensure username is visible in UI
+ {
+ await username.FocusAsync();
+ }
+ }
+ else
+ {
+ if (!string.IsNullOrEmpty(password.Id)) // ensure password is visible in UI
+ {
+ await password.FocusAsync();
+ }
}
}
diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor
index 4decf197..4eebbbcb 100644
--- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor
+++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Create.razor
@@ -1,6 +1,7 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@using System.Text.RegularExpressions
+@using System.Reflection
@inject NavigationManager NavigationManager
@inject IModuleDefinitionService ModuleDefinitionService
@inject IModuleService ModuleService
@@ -97,6 +98,16 @@
{
AddModuleMessage(Localizer["Info.Module.Development"], MessageType.Info);
}
+ else
+ {
+ var entryAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
+ if (entryAssemblyName.EndsWith(".Oqtane"))
+ {
+ // Oqtane Application assemblies end with .Server.Oqtane or .Client.Oqtane
+ string[] segments = entryAssemblyName.Split('.');
+ _owner = string.Join(".", segments, 0, segments.Length - 2);
+ }
+ }
}
protected override async Task OnParametersSetAsync()
diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor
index 525f45df..0ceec1fd 100644
--- a/Oqtane.Client/Modules/Admin/Site/Index.razor
+++ b/Oqtane.Client/Modules/Admin/Site/Index.razor
@@ -411,6 +411,18 @@