diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor
index f8766bab..3071d436 100644
--- a/Oqtane.Client/Modules/Admin/Login/Index.razor
+++ b/Oqtane.Client/Modules/Admin/Login/Index.razor
@@ -4,11 +4,12 @@
@using Oqtane.Models
@using Oqtane.Services
@using Oqtane.Providers
+@using Oqtane.Shared
@inherits ModuleBase
@inject IUriHelper UriHelper
@inject IJSRuntime jsRuntime
@inject IUserService UserService
-@inject ServerAuthenticationStateProvider AuthStateProvider
+@inject IServiceProvider ServiceProvider
@@ -28,33 +29,62 @@
+
- Cancel
+
@code {
- public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
+public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
- public string Message { get; set; } = "
Use host/password For Demo Access
";
- public string Username { get; set; } = "";
- public string Password { get; set; } = "";
+public string Message { get; set; } = "Use host/password For Demo Access
";
+public string Username { get; set; } = "";
+public string Password { get; set; } = "";
+public bool Remember { get; set; } = false;
- private async Task Login()
+private async Task Login()
+{
+ User user = new User();
+ user.Username = Username;
+ user.Password = Password;
+ user.IsPersistent = Remember;
+ user = await UserService.LoginUserAsync(user);
+ if (user.IsAuthenticated)
{
- User user = new User();
- user.Username = Username;
- user.Password = Password;
- user = await UserService.LoginUserAsync(user);
- if (user != null)
+ string ReturnUrl = PageState.QueryString["returnurl"];
+
+ var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
+ if (authstateprovider == null)
{
- AuthStateProvider.NotifyAuthenticationChanged();
- UriHelper.NavigateTo(NavigateUrl("", true));
+ // server-side Blazor
+ var interop = new Interop(jsRuntime);
+ string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
+ var fields = new { __RequestVerificationToken = antiforgerytoken, username = Username, password = Password, remember = Remember, returnurl = ReturnUrl };
+ await interop.SubmitForm("/login/", fields);
}
else
{
- Message = "User Does Not Exist
";
+ // client-side Blazor
+ authstateprovider.NotifyAuthenticationChanged();
+ UriHelper.NavigateTo(NavigateUrl(ReturnUrl, true));
}
}
+ else
+ {
+ Message = "Login Failed. Please Remember That Passwords Are Case Sensitive.
";
+ }
+}
+
+private void Cancel()
+{
+ string ReturnUrl = PageState.QueryString["returnurl"];
+ UriHelper.NavigateTo(NavigateUrl(ReturnUrl));
+}
}
diff --git a/Oqtane.Client/Providers/ServerAuthenticationStateProvider.cs b/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs
similarity index 84%
rename from Oqtane.Client/Providers/ServerAuthenticationStateProvider.cs
rename to Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs
index 818ed0c7..9ad5b1c7 100644
--- a/Oqtane.Client/Providers/ServerAuthenticationStateProvider.cs
+++ b/Oqtane.Client/Providers/IdentityAuthenticationStateProvider.cs
@@ -7,14 +7,12 @@ using Oqtane.Models;
namespace Oqtane.Providers
{
- public class ServerAuthenticationStateProvider : AuthenticationStateProvider
+ public class IdentityAuthenticationStateProvider : AuthenticationStateProvider
{
- //private readonly IUserService UserService;
private readonly IUriHelper urihelper;
- public ServerAuthenticationStateProvider(IUriHelper urihelper)
+ public IdentityAuthenticationStateProvider(IUriHelper urihelper)
{
- //this.UserService = UserService;
this.urihelper = urihelper;
}
@@ -25,6 +23,7 @@ namespace Oqtane.Providers
Uri uri = new Uri(urihelper.GetAbsoluteUri());
string apiurl = uri.Scheme + "://" + uri.Authority + "/~/api/User/authenticate";
User user = await http.GetJsonAsync(apiurl);
+
var identity = user.IsAuthenticated
? new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, user.Username) }, "Identity.Application")
: new ClaimsIdentity();
diff --git a/Oqtane.Client/Services/AliasService.cs b/Oqtane.Client/Services/AliasService.cs
index acc81b47..88aa9683 100644
--- a/Oqtane.Client/Services/AliasService.cs
+++ b/Oqtane.Client/Services/AliasService.cs
@@ -32,8 +32,7 @@ namespace Oqtane.Services
public async Task GetAliasAsync(int AliasId)
{
- List aliases = await http.GetJsonAsync>(apiurl);
- return aliases.Where(item => item.AliasId == AliasId).FirstOrDefault();
+ return await http.GetJsonAsync(apiurl + "/" + AliasId.ToString());
}
public async Task AddAliasAsync(Alias alias)
diff --git a/Oqtane.Client/Services/IModuleService.cs b/Oqtane.Client/Services/IModuleService.cs
index 73143fc2..4f800cf7 100644
--- a/Oqtane.Client/Services/IModuleService.cs
+++ b/Oqtane.Client/Services/IModuleService.cs
@@ -8,6 +8,7 @@ namespace Oqtane.Services
{
Task> GetModulesAsync(int PageId);
Task> GetModulesAsync(int SiteId, string ModuleDefinitionName);
+ Task GetModuleAsync(int ModuleId);
Task AddModuleAsync(Module module);
Task UpdateModuleAsync(Module module);
Task DeleteModuleAsync(int ModuleId);
diff --git a/Oqtane.Client/Services/IPageService.cs b/Oqtane.Client/Services/IPageService.cs
index 71e0ea0c..5388af7b 100644
--- a/Oqtane.Client/Services/IPageService.cs
+++ b/Oqtane.Client/Services/IPageService.cs
@@ -7,6 +7,7 @@ namespace Oqtane.Services
public interface IPageService
{
Task> GetPagesAsync(int SiteId);
+ Task GetPageAsync(int PageId);
Task AddPageAsync(Page page);
Task UpdatePageAsync(Page page);
Task DeletePageAsync(int PageId);
diff --git a/Oqtane.Client/Services/IUserService.cs b/Oqtane.Client/Services/IUserService.cs
index c11e8e80..e1b42bdd 100644
--- a/Oqtane.Client/Services/IUserService.cs
+++ b/Oqtane.Client/Services/IUserService.cs
@@ -10,6 +10,8 @@ namespace Oqtane.Services
Task GetUserAsync(int UserId);
+ Task GetUserAsync(string Username);
+
Task AddUserAsync(User user);
Task UpdateUserAsync(User user);
diff --git a/Oqtane.Client/Services/ModuleService.cs b/Oqtane.Client/Services/ModuleService.cs
index 3b4b6d74..ede01dc5 100644
--- a/Oqtane.Client/Services/ModuleService.cs
+++ b/Oqtane.Client/Services/ModuleService.cs
@@ -39,6 +39,11 @@ namespace Oqtane.Services
return modules.ToList();
}
+ public async Task GetModuleAsync(int ModuleId)
+ {
+ return await http.GetJsonAsync(apiurl + "/" + ModuleId.ToString());
+ }
+
public async Task AddModuleAsync(Module module)
{
await http.PostJsonAsync(apiurl, module);
diff --git a/Oqtane.Client/Services/PageService.cs b/Oqtane.Client/Services/PageService.cs
index 172d7950..fb54c32c 100644
--- a/Oqtane.Client/Services/PageService.cs
+++ b/Oqtane.Client/Services/PageService.cs
@@ -30,6 +30,11 @@ namespace Oqtane.Services
return pages.OrderBy(item => item.Order).ToList();
}
+ public async Task GetPageAsync(int PageId)
+ {
+ return await http.GetJsonAsync(apiurl + "/" + PageId.ToString());
+ }
+
public async Task AddPageAsync(Page page)
{
await http.PostJsonAsync(apiurl, page);
diff --git a/Oqtane.Client/Services/SiteService.cs b/Oqtane.Client/Services/SiteService.cs
index 7d7d135e..519155a5 100644
--- a/Oqtane.Client/Services/SiteService.cs
+++ b/Oqtane.Client/Services/SiteService.cs
@@ -32,17 +32,7 @@ namespace Oqtane.Services
public async Task GetSiteAsync(int SiteId)
{
- List sites = await http.GetJsonAsync>(apiurl);
- Site site;
- if (sites.Count == 1)
- {
- site = sites.FirstOrDefault();
- }
- else
- {
- site = sites.Where(item => item.SiteId == SiteId).FirstOrDefault();
- }
- return site;
+ return await http.GetJsonAsync(apiurl + "/" + SiteId.ToString());
}
public async Task AddSiteAsync(Site site)
diff --git a/Oqtane.Client/Services/UserService.cs b/Oqtane.Client/Services/UserService.cs
index fbe718e1..d83dc260 100644
--- a/Oqtane.Client/Services/UserService.cs
+++ b/Oqtane.Client/Services/UserService.cs
@@ -35,8 +35,12 @@ namespace Oqtane.Services
public async Task GetUserAsync(int UserId)
{
- List users = await http.GetJsonAsync>(apiurl);
- return users.Where(item => item.UserId == UserId).FirstOrDefault();
+ return await http.GetJsonAsync(apiurl + "/" + UserId.ToString());
+ }
+
+ public async Task GetUserAsync(string Username)
+ {
+ return await http.GetJsonAsync(apiurl + "/name/" + Username);
}
public async Task AddUserAsync(User user)
diff --git a/Oqtane.Client/Shared/Interop.cs b/Oqtane.Client/Shared/Interop.cs
index 38acd4bf..3ece9f1d 100644
--- a/Oqtane.Client/Shared/Interop.cs
+++ b/Oqtane.Client/Shared/Interop.cs
@@ -13,17 +13,18 @@ namespace Oqtane.Shared
this.jsRuntime = jsRuntime;
}
- public Task SetCookie(string name, string value, int days)
+ public Task SetCookie(string name, string value, int days)
{
try
{
- return jsRuntime.InvokeAsync(
+ jsRuntime.InvokeAsync(
"interop.setCookie",
name, value, days);
+ return Task.CompletedTask;
}
catch
{
- return Task.FromResult(string.Empty);
+ return Task.CompletedTask;
}
}
@@ -41,18 +42,48 @@ namespace Oqtane.Shared
}
}
- public Task AddCSS(string filename)
+ public Task AddCSS(string filename)
+ {
+ try
+ {
+ jsRuntime.InvokeAsync(
+ "interop.addCSS",
+ filename);
+ return Task.CompletedTask;
+ }
+ catch
+ {
+ return Task.CompletedTask;
+ }
+ }
+
+ public Task GetElementByName(string name)
{
try
{
return jsRuntime.InvokeAsync(
- "interop.addCSS",
- filename);
+ "interop.getElementByName",
+ name);
}
catch
{
return Task.FromResult(string.Empty);
}
}
+
+ public Task SubmitForm(string path, object fields)
+ {
+ try
+ {
+ jsRuntime.InvokeAsync(
+ "interop.submitForm",
+ path, fields);
+ return Task.CompletedTask;
+ }
+ catch
+ {
+ return Task.CompletedTask;
+ }
+ }
}
}
diff --git a/Oqtane.Client/Shared/SiteRouter.razor b/Oqtane.Client/Shared/SiteRouter.razor
index b2cf5ab4..b8ec1bd2 100644
--- a/Oqtane.Client/Shared/SiteRouter.razor
+++ b/Oqtane.Client/Shared/SiteRouter.razor
@@ -127,7 +127,7 @@ private async Task Refresh()
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
if (authState.User.Identity.IsAuthenticated)
{
- user = await UserService.GetCurrentUserAsync();
+ user = await UserService.GetUserAsync(authState.User.Identity.Name);
}
}
else
diff --git a/Oqtane.Client/Shared/Utilities.cs b/Oqtane.Client/Shared/Utilities.cs
index 410e2b0e..9de11332 100644
--- a/Oqtane.Client/Shared/Utilities.cs
+++ b/Oqtane.Client/Shared/Utilities.cs
@@ -25,7 +25,14 @@ namespace Oqtane.Shared
string url = pagestate.Alias.Path + "/" + path;
if (reload)
{
- url += "?reload=true";
+ if (url.Contains("?"))
+ {
+ url += "&reload=true";
+ }
+ else
+ {
+ url += "?reload=true";
+ }
}
return url;
}
diff --git a/Oqtane.Client/Startup.cs b/Oqtane.Client/Startup.cs
index 3ed914c5..b817e046 100644
--- a/Oqtane.Client/Startup.cs
+++ b/Oqtane.Client/Startup.cs
@@ -31,8 +31,8 @@ namespace Oqtane.Client
{
// register auth services
services.AddAuthorizationCore();
- services.AddScoped();
- services.AddScoped(s => s.GetRequiredService());
+ services.AddScoped();
+ services.AddScoped(s => s.GetRequiredService());
// register scoped core services
services.AddScoped();
diff --git a/Oqtane.Client/Themes/Controls/Login.razor b/Oqtane.Client/Themes/Controls/Login.razor
index 898f9c0b..cae8a035 100644
--- a/Oqtane.Client/Themes/Controls/Login.razor
+++ b/Oqtane.Client/Themes/Controls/Login.razor
@@ -1,10 +1,14 @@
@using Oqtane.Themes
@using Oqtane.Services
@using Oqtane.Providers
+@using Oqtane.Shared
+@using Oqtane.Models
+@using Microsoft.JSInterop
@inherits ThemeObjectBase
@inject IUriHelper UriHelper
@inject IUserService UserService
-@inject ServerAuthenticationStateProvider AuthStateProvider
+@inject IJSRuntime jsRuntime
+@inject IServiceProvider ServiceProvider
@@ -22,13 +26,25 @@
@code {
private void LoginUser()
{
- UriHelper.NavigateTo(NavigateUrl("login"));
+ UriHelper.NavigateTo(NavigateUrl("login?returnurl=" + PageState.Page.Path));
}
private async Task LogoutUser()
{
await UserService.LogoutUserAsync();
- AuthStateProvider.NotifyAuthenticationChanged();
- UriHelper.NavigateTo(NavigateUrl("", true));
+
+ var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
+ if (authstateprovider == null)
+ {
+ // server-side Blazor
+ var interop = new Interop(jsRuntime);
+ await interop.SubmitForm("/logout/", "");
+ }
+ else
+ {
+ // client-side Blazor
+ authstateprovider.NotifyAuthenticationChanged();
+ UriHelper.NavigateTo(NavigateUrl("login", true));
+ }
}
}
diff --git a/Oqtane.Client/wwwroot/js/interop.js b/Oqtane.Client/wwwroot/js/interop.js
index b6beef83..a322ca40 100644
--- a/Oqtane.Client/wwwroot/js/interop.js
+++ b/Oqtane.Client/wwwroot/js/interop.js
@@ -29,5 +29,23 @@ window.interop = {
link.href = fileName;
head.appendChild(link);
+ },
+ submitForm: function (path, fields) {
+ const form = document.createElement('form');
+ form.method = 'post';
+ form.action = path;
+
+ for (const key in fields) {
+ if (fields.hasOwnProperty(key)) {
+ const hiddenField = document.createElement('input');
+ hiddenField.type = 'hidden';
+ hiddenField.name = key;
+ hiddenField.value = fields[key];
+ form.appendChild(hiddenField);
+ }
+ }
+
+ document.body.appendChild(form);
+ form.submit();
}
};
diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs
index cfad0479..759515ee 100644
--- a/Oqtane.Server/Controllers/UserController.cs
+++ b/Oqtane.Server/Controllers/UserController.cs
@@ -4,6 +4,8 @@ using Oqtane.Repository;
using Oqtane.Models;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
+using Microsoft.Extensions.Primitives;
+using System.Security.Claims;
namespace Oqtane.Controllers
{
@@ -34,7 +36,7 @@ namespace Oqtane.Controllers
{
return users.GetUser(id);
}
-
+
// POST api/
[HttpPost]
public async Task Post([FromBody] User user)
@@ -73,54 +75,48 @@ namespace Oqtane.Controllers
users.DeleteUser(id);
}
- // GET api//current
- [HttpGet("current")]
- public User Current()
+ // GET api//name/x
+ [HttpGet("name/{name}")]
+ public User GetByName(string name)
{
- User user = null;
- if (User.Identity.IsAuthenticated)
- {
- user = users.GetUser(User.Identity.Name);
- user.IsAuthenticated = true;
- }
- return user;
+ return users.GetUser(name);
}
// POST api//login
[HttpPost("login")]
public async Task Login([FromBody] User user)
{
+ // TODO: seed host user - this logic should be moved to installation
+ IdentityUser identityuser = await identityUserManager.FindByNameAsync("host");
+ if (identityuser == null)
+ {
+ var result = await identityUserManager.CreateAsync(new IdentityUser { UserName = "host", Email = "host" }, "password");
+ if (result.Succeeded)
+ {
+ users.AddUser(new Models.User { Username = "host", DisplayName = "host", IsSuperUser = true, Roles = "" });
+ }
+ }
+
if (ModelState.IsValid)
{
- // seed host user - this logic should be moved to installation
- IdentityUser identityuser = await identityUserManager.FindByNameAsync("host");
- if (identityuser == null)
- {
- var result = await identityUserManager.CreateAsync(new IdentityUser { UserName = "host", Email = "host" }, "password");
- if (result.Succeeded)
- {
- users.AddUser(new Models.User { Username = "host", DisplayName = "host", IsSuperUser = true, Roles = "" });
- }
- }
-
identityuser = await identityUserManager.FindByNameAsync(user.Username);
if (identityuser != null)
{
var result = await identitySignInManager.CheckPasswordSignInAsync(identityuser, user.Password, false);
if (result.Succeeded)
{
- await identitySignInManager.SignInAsync(identityuser, false);
+ await identitySignInManager.SignInAsync(identityuser, user.IsPersistent);
user = users.GetUser(identityuser.UserName);
user.IsAuthenticated = true;
}
else
{
- user = null;
+ user = new Models.User { Username = user.Username, IsAuthenticated = false };
}
}
else
{
- user = null;
+ user = new Models.User { Username = user.Username, IsAuthenticated = false };
}
}
return user;
diff --git a/Oqtane.Server/Pages/Login.cshtml b/Oqtane.Server/Pages/Login.cshtml
new file mode 100644
index 00000000..b0240ac6
--- /dev/null
+++ b/Oqtane.Server/Pages/Login.cshtml
@@ -0,0 +1,3 @@
+@page "/login"
+@namespace Oqtane.Pages
+@model Oqtane.Pages.LoginModel
diff --git a/Oqtane.Server/Pages/Login.cshtml.cs b/Oqtane.Server/Pages/Login.cshtml.cs
new file mode 100644
index 00000000..ed88df50
--- /dev/null
+++ b/Oqtane.Server/Pages/Login.cshtml.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace Oqtane.Pages
+{
+ [AllowAnonymous]
+ public class LoginModel : PageModel
+ {
+
+ private readonly UserManager identityUserManager;
+ private readonly SignInManager identitySignInManager;
+
+ public LoginModel(UserManager IdentityUserManager, SignInManager IdentitySignInManager)
+ {
+ identityUserManager = IdentityUserManager;
+ identitySignInManager = IdentitySignInManager;
+ }
+
+ public async Task OnPostAsync(string username, string password, bool remember, string returnurl)
+ {
+ await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
+
+ bool validuser = false;
+ IdentityUser identityuser = await identityUserManager.FindByNameAsync(username);
+ if (identityuser != null)
+ {
+ var result = await identitySignInManager.CheckPasswordSignInAsync(identityuser, password, false);
+ if (result.Succeeded)
+ {
+ validuser = true;
+ }
+ }
+
+ if (validuser)
+ {
+ var claims = new List{ new Claim(ClaimTypes.Name, username) };
+ var claimsIdentity = new ClaimsIdentity(claims, IdentityConstants.ApplicationScheme);
+ var authProperties = new AuthenticationProperties{IsPersistent = remember};
+ await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme, new ClaimsPrincipal(claimsIdentity), authProperties);
+ }
+
+ return LocalRedirect(Url.Content("~/" + returnurl));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Oqtane.Server/Pages/Logout.cshtml b/Oqtane.Server/Pages/Logout.cshtml
new file mode 100644
index 00000000..75a9fd7e
--- /dev/null
+++ b/Oqtane.Server/Pages/Logout.cshtml
@@ -0,0 +1,3 @@
+@page "/logout"
+@namespace Oqtane.Pages
+@model Oqtane.Pages.LogoutModel
diff --git a/Oqtane.Server/Pages/Logout.cshtml.cs b/Oqtane.Server/Pages/Logout.cshtml.cs
new file mode 100644
index 00000000..f66575c4
--- /dev/null
+++ b/Oqtane.Server/Pages/Logout.cshtml.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Oqtane.Models;
+
+namespace Oqtane.Pages
+{
+ [IgnoreAntiforgeryToken(Order = 1001)]
+ [AllowAnonymous]
+ public class LogoutModel : PageModel
+ {
+ public async Task OnPostAsync()
+ {
+ await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme);
+
+ return LocalRedirect(Url.Content("~/"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml
index af42db3b..30862539 100644
--- a/Oqtane.Server/Pages/_Host.cshtml
+++ b/Oqtane.Server/Pages/_Host.cshtml
@@ -14,6 +14,7 @@
+ @(Html.AntiForgeryToken())
@(await Html.RenderComponentAsync())
diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
index 298bfd84..a16572fe 100644
--- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
+++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
@@ -52,6 +52,7 @@ namespace Oqtane.Repository
{
/// determine if this module implements IModule
Type moduletype = assembly.GetTypes()
+ .Where(item => item.Namespace != null)
.Where(item => item.Namespace.StartsWith(ModuleType))
.Where(item => item.GetInterfaces().Contains(typeof(IModule)))
.FirstOrDefault();
diff --git a/Oqtane.Server/Repository/TenantResolver.cs b/Oqtane.Server/Repository/TenantResolver.cs
index 4ba145ff..4685f9cd 100644
--- a/Oqtane.Server/Repository/TenantResolver.cs
+++ b/Oqtane.Server/Repository/TenantResolver.cs
@@ -24,7 +24,7 @@ namespace Oqtane.Repository
aliasname = accessor.HttpContext.Request.Host.Value;
string path = accessor.HttpContext.Request.Path.Value;
string[] segments = path.Split('/');
- if (segments[1] != "~")
+ if (segments[0] == "api" && segments[1] != "~")
{
aliasname += "/" + segments[1];
}
diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs
index 2c02cf2c..aec59868 100644
--- a/Oqtane.Server/Repository/ThemeRepository.cs
+++ b/Oqtane.Server/Repository/ThemeRepository.cs
@@ -52,6 +52,7 @@ namespace Oqtane.Repository
{
/// determine if this theme implements ITheme
Type themeType = assembly.GetTypes()
+ .Where(item => item.Namespace != null)
.Where(item => item.Namespace.StartsWith(Namespace))
.Where(item => item.GetInterfaces().Contains(typeof(ITheme))).FirstOrDefault();
if (themeType != null)
@@ -105,7 +106,10 @@ namespace Oqtane.Repository
theme.ThemeControls += (themeControlType.FullName + ", " + typename[1] + ";");
}
// containers
- Type[] containertypes = assembly.GetTypes().Where(item => item.Namespace.StartsWith(Namespace)).Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
+ Type[] containertypes = assembly.GetTypes()
+ .Where(item => item.Namespace != null)
+ .Where(item => item.Namespace.StartsWith(Namespace))
+ .Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
foreach (Type containertype in containertypes)
{
theme.ContainerControls += (containertype.FullName + ", " + typename[1] + ";");
diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs
index 0e29d5df..ab2de131 100644
--- a/Oqtane.Server/Startup.cs
+++ b/Oqtane.Server/Startup.cs
@@ -17,12 +17,9 @@ using System.Runtime.Loader;
using Oqtane.Services;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
-using Oqtane.Client;
using Oqtane.Shared;
using Microsoft.AspNetCore.Identity;
-using Oqtane.Providers;
using System.Threading.Tasks;
-using Microsoft.AspNetCore.Authentication.Cookies;
namespace Oqtane.Server
{
@@ -47,25 +44,27 @@ namespace Oqtane.Server
services.AddRazorPages();
services.AddServerSideBlazor();
- // server-side Blazor does not register HttpClient by default
+ // setup HttpClient for server side in a client side compatible fashion ( with auth cookie )
if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
{
- // setup HttpClient for server side in a client side compatible fashion
services.AddScoped(s =>
{
// creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
var uriHelper = s.GetRequiredService();
- return new HttpClient
+ var httpContextAccessor = s.GetRequiredService();
+ var authToken = httpContextAccessor.HttpContext.Request.Cookies[".AspNetCore.Identity.Application"];
+ var client = new HttpClient(new HttpClientHandler { UseCookies = false });
+ if (authToken != null)
{
- BaseAddress = new Uri(uriHelper.GetBaseUri())
- };
+ client.DefaultRequestHeaders.Add("Cookie", ".AspNetCore.Identity.Application=" + authToken);
+ }
+ client.BaseAddress = new Uri(uriHelper.GetBaseUri());
+ return client;
});
}
- // register auth services
+ // register auth services
services.AddAuthorizationCore();
- services.AddScoped();
- services.AddScoped(s => s.GetRequiredService());
// register scoped core services
services.AddScoped();
diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js
index b6beef83..db61ecbe 100644
--- a/Oqtane.Server/wwwroot/js/interop.js
+++ b/Oqtane.Server/wwwroot/js/interop.js
@@ -20,6 +20,14 @@ window.interop = {
}
return "";
},
+ getElementByName: function (name) {
+ var elements = document.getElementsByName(name);
+ if (elements.length) {
+ return elements[0].value;
+ } else {
+ return "";
+ }
+ },
addCSS: function (fileName) {
var head = document.head;
var link = document.createElement("link");
@@ -29,5 +37,23 @@ window.interop = {
link.href = fileName;
head.appendChild(link);
+ },
+ submitForm: function (path, fields) {
+ const form = document.createElement('form');
+ form.method = 'post';
+ form.action = path;
+
+ for (const key in fields) {
+ if (fields.hasOwnProperty(key)) {
+ const hiddenField = document.createElement('input');
+ hiddenField.type = 'hidden';
+ hiddenField.name = key;
+ hiddenField.value = fields[key];
+ form.appendChild(hiddenField);
+ }
+ }
+
+ document.body.appendChild(form);
+ form.submit();
}
};
diff --git a/Oqtane.Shared/Models/User.cs b/Oqtane.Shared/Models/User.cs
index d2bd5f6d..34b27776 100644
--- a/Oqtane.Shared/Models/User.cs
+++ b/Oqtane.Shared/Models/User.cs
@@ -14,5 +14,7 @@ namespace Oqtane.Models
public string Password { get; set; }
[NotMapped]
public bool IsAuthenticated { get; set; }
+ [NotMapped]
+ public bool IsPersistent { get; set; }
}
}