Merge pull request #37 from sbwalker/master
Integrated AuthenticatedStateProvider using .NET Core Identity. Solution works fine when running in client-side mode ( Wasm build profile ) but does not set cookie in server-side mode.
This commit is contained in:
commit
61171e4844
|
@ -1,9 +1,11 @@
|
||||||
@using Oqtane.Shared
|
@using Oqtane.Shared
|
||||||
@using Oqtane.Client.Shared
|
@using Oqtane.Client.Shared
|
||||||
|
|
||||||
<CascadingValue Value="@PageState">
|
<CascadingAuthenticationState>
|
||||||
<SiteRouter OnStateChange="@ChangeState" />
|
<CascadingValue Value="@PageState">
|
||||||
</CascadingValue>
|
<SiteRouter OnStateChange="@ChangeState" />
|
||||||
|
</CascadingValue>
|
||||||
|
</CascadingAuthenticationState>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private PageState PageState { get; set; }
|
private PageState PageState { get; set; }
|
||||||
|
|
|
@ -1,45 +1,56 @@
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
@using Oqtane.Shared
|
|
||||||
@using Oqtane.Modules
|
@using Oqtane.Modules
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using Oqtane.Models
|
@using Oqtane.Models
|
||||||
@using Oqtane.Services
|
@using Oqtane.Services
|
||||||
@using Oqtane.Client.Modules.Controls
|
@using Oqtane.Providers
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IUriHelper UriHelper
|
@inject IUriHelper UriHelper
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IJSRuntime jsRuntime
|
||||||
@inject IUserService UserService
|
@inject IUserService UserService
|
||||||
|
@inject ServerAuthenticationStateProvider AuthStateProvider
|
||||||
|
|
||||||
<div class="container">
|
<AuthorizeView>
|
||||||
@((MarkupString)Message)
|
<Authorizing>
|
||||||
<div class="form-group">
|
<text>...</text>
|
||||||
<label for="Username" class="control-label">Username: </label>
|
</Authorizing>
|
||||||
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Username" />
|
<Authorized>
|
||||||
</div>
|
You are already logged in
|
||||||
<div class="form-group">
|
</Authorized>
|
||||||
<label for="Password" class="control-label">Password: </label>
|
<NotAuthorized>
|
||||||
<input type="password" name="Password" class="form-control" placeholder="Password" @bind="@Password" />
|
<div class="container">
|
||||||
</div>
|
@((MarkupString)Message)
|
||||||
<button type="button" class="btn btn-primary" @onclick="@Login">Login</button>
|
<div class="form-group">
|
||||||
<NavLink class="btn btn-secondary" href="/">Cancel</NavLink>
|
<label for="Username" class="control-label">Username: </label>
|
||||||
</div>
|
<input type="text" name="Username" class="form-control" placeholder="Username" @bind="@Username" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="Password" class="control-label">Password: </label>
|
||||||
|
<input type="password" name="Password" class="form-control" placeholder="Password" @bind="@Password" />
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@Login">Login</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="/">Cancel</NavLink>
|
||||||
|
</div>
|
||||||
|
</NotAuthorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
|
public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
|
||||||
|
|
||||||
public string Message { get; set; } = "<div class=\"alert alert-info\" role=\"alert\">Use host/host For Demo Access</div>";
|
public string Message { get; set; } = "<div class=\"alert alert-info\" role=\"alert\">Use host/password For Demo Access</div>";
|
||||||
public string Username { get; set; } = "";
|
public string Username { get; set; } = "";
|
||||||
public string Password { get; set; } = "";
|
public string Password { get; set; } = "";
|
||||||
|
|
||||||
private async Task Login()
|
private async Task Login()
|
||||||
{
|
{
|
||||||
List<User> users = await UserService.GetUsersAsync();
|
User user = new User();
|
||||||
User user = users.Where(item => item.Username == Username).FirstOrDefault();
|
user.Username = Username;
|
||||||
|
user.Password = Password;
|
||||||
|
user = await UserService.LoginUserAsync(user);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
var interop = new Interop(jsRuntime);
|
AuthStateProvider.NotifyAuthenticationChanged();
|
||||||
await interop.SetCookie("user", user.UserId.ToString(), 7);
|
UriHelper.NavigateTo(NavigateUrl(""));
|
||||||
UriHelper.NavigateTo(NavigateUrl(""), true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
@using Oqtane.Shared
|
|
||||||
@using Oqtane.Modules
|
@using Oqtane.Modules
|
||||||
@using Microsoft.JSInterop
|
@using Oqtane.Models
|
||||||
@using Oqtane.Client.Modules.Controls
|
@using Oqtane.Services
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject IUriHelper UriHelper
|
@inject IUriHelper UriHelper
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IUserService UserService
|
||||||
|
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -17,13 +15,25 @@
|
||||||
<label for="Password" class="control-label">Password: </label>
|
<label for="Password" class="control-label">Password: </label>
|
||||||
<input type="password" name="Password" class="form-control" placeholder="Password" @bind="@Password" />
|
<input type="password" name="Password" class="form-control" placeholder="Password" @bind="@Password" />
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn btn-primary">Register</button>
|
<button type="button" class="btn btn-primary" @onclick="@RegisterUser">Register</button>
|
||||||
<NavLink class="btn btn-secondary" href="/">Cancel</NavLink>
|
<NavLink class="btn btn-secondary" href="/">Cancel</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
|
public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
|
||||||
|
|
||||||
public string Username { get; set; } = "";
|
public string Username { get; set; } = "";
|
||||||
public string Password { get; set; } = "";
|
public string Password { get; set; } = "";
|
||||||
|
|
||||||
|
private async Task RegisterUser()
|
||||||
|
{
|
||||||
|
User user = new User();
|
||||||
|
user.Username = Username;
|
||||||
|
user.DisplayName = Username;
|
||||||
|
user.Roles = "Administrators;";
|
||||||
|
user.IsSuperUser = false;
|
||||||
|
user.Password = Password;
|
||||||
|
await UserService.AddUserAsync(user);
|
||||||
|
UriHelper.NavigateTo("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
39
Oqtane.Client/Providers/ServerAuthenticationStateProvider.cs
Normal file
39
Oqtane.Client/Providers/ServerAuthenticationStateProvider.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Providers
|
||||||
|
{
|
||||||
|
public class ServerAuthenticationStateProvider : AuthenticationStateProvider
|
||||||
|
{
|
||||||
|
//private readonly IUserService UserService;
|
||||||
|
private readonly IUriHelper urihelper;
|
||||||
|
|
||||||
|
public ServerAuthenticationStateProvider(IUriHelper urihelper)
|
||||||
|
{
|
||||||
|
//this.UserService = UserService;
|
||||||
|
this.urihelper = urihelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
|
{
|
||||||
|
// hack: create a new HttpClient rather than relying on the registered service as the AuthenticationStateProvider is initialized prior to IUriHelper ( https://github.com/aspnet/AspNetCore/issues/11867 )
|
||||||
|
HttpClient http = new HttpClient();
|
||||||
|
Uri uri = new Uri(urihelper.GetAbsoluteUri());
|
||||||
|
string apiurl = uri.Scheme + "://" + uri.Authority + "/~/api/User/authenticate";
|
||||||
|
User user = await http.GetJsonAsync<User>(apiurl);
|
||||||
|
var identity = user.IsAuthenticated
|
||||||
|
? new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, user.Username) }, "Identity.Application")
|
||||||
|
: new ClaimsIdentity();
|
||||||
|
return new AuthenticationState(new ClaimsPrincipal(identity));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NotifyAuthenticationChanged()
|
||||||
|
{
|
||||||
|
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,12 @@ namespace Oqtane.Services
|
||||||
|
|
||||||
Task DeleteUserAsync(int UserId);
|
Task DeleteUserAsync(int UserId);
|
||||||
|
|
||||||
|
Task<User> GetCurrentUserAsync();
|
||||||
|
|
||||||
|
Task<User> LoginUserAsync(User user);
|
||||||
|
|
||||||
|
Task LogoutUserAsync();
|
||||||
|
|
||||||
bool IsAuthorized(User user, string accesscontrollist);
|
bool IsAuthorized(User user, string accesscontrollist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,13 @@ namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
private readonly HttpClient http;
|
private readonly HttpClient http;
|
||||||
private readonly SiteState sitestate;
|
private readonly SiteState sitestate;
|
||||||
|
private readonly IUriHelper urihelper;
|
||||||
|
|
||||||
public UserService(HttpClient http, SiteState sitestate)
|
public UserService(HttpClient http, SiteState sitestate, IUriHelper urihelper)
|
||||||
{
|
{
|
||||||
this.http = http;
|
this.http = http;
|
||||||
this.sitestate = sitestate;
|
this.sitestate = sitestate;
|
||||||
|
this.urihelper = urihelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string apiurl
|
private string apiurl
|
||||||
|
@ -35,7 +37,7 @@ namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
List<User> users = await http.GetJsonAsync<List<User>>(apiurl);
|
List<User> users = await http.GetJsonAsync<List<User>>(apiurl);
|
||||||
return users.Where(item => item.UserId == UserId).FirstOrDefault();
|
return users.Where(item => item.UserId == UserId).FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddUserAsync(User user)
|
public async Task AddUserAsync(User user)
|
||||||
{
|
{
|
||||||
|
@ -51,6 +53,22 @@ namespace Oqtane.Services
|
||||||
await http.DeleteAsync(apiurl + "/" + UserId.ToString());
|
await http.DeleteAsync(apiurl + "/" + UserId.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<User> GetCurrentUserAsync()
|
||||||
|
{
|
||||||
|
return await http.GetJsonAsync<User>(apiurl + "/current");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<User> LoginUserAsync(User user)
|
||||||
|
{
|
||||||
|
return await http.PostJsonAsync<User>(apiurl + "/login", user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LogoutUserAsync()
|
||||||
|
{
|
||||||
|
// best practices recommend post is preferrable to get for logout
|
||||||
|
await http.PostJsonAsync(apiurl + "/logout", null);
|
||||||
|
}
|
||||||
|
|
||||||
// ACLs are stored in the format "!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]" where "!" designates Deny permissions
|
// ACLs are stored in the format "!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]" where "!" designates Deny permissions
|
||||||
public bool IsAuthorized(User user, string accesscontrollist)
|
public bool IsAuthorized(User user, string accesscontrollist)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
@using Oqtane.Shared
|
@using Oqtane.Shared
|
||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Microsoft.AspNetCore.Components.Routing
|
||||||
|
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||||
@inject SiteState SiteState
|
@inject SiteState SiteState
|
||||||
@inject IUriHelper UriHelper
|
@inject IUriHelper UriHelper
|
||||||
@inject INavigationInterception NavigationInterception
|
@inject INavigationInterception NavigationInterception
|
||||||
|
@ -106,15 +107,13 @@ private async Task Refresh()
|
||||||
}
|
}
|
||||||
if (site != null || reload == true)
|
if (site != null || reload == true)
|
||||||
{
|
{
|
||||||
var interop = new Interop(jsRuntime);
|
|
||||||
string userid = await interop.GetCookie("user");
|
|
||||||
|
|
||||||
user = null;
|
user = null;
|
||||||
if (PageState == null || reload == true)
|
if (PageState == null || reload == true)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(userid))
|
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
|
||||||
|
if (authState.User.Identity.IsAuthenticated)
|
||||||
{
|
{
|
||||||
user = await UserService.GetUserAsync(int.Parse(userid));
|
user = await UserService.GetCurrentUserAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -122,23 +121,6 @@ private async Task Refresh()
|
||||||
user = PageState.User;
|
user = PageState.User;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(userid))
|
|
||||||
{
|
|
||||||
if (user != null && user.UserId != int.Parse(userid))
|
|
||||||
{
|
|
||||||
user = await UserService.GetUserAsync(int.Parse(userid));
|
|
||||||
}
|
|
||||||
// this is a hack for server-side Blazor where JSInterop is not working OnInit() which means the userid is not being retrieved from the cookie on the initial render and is not being loaded into PageState
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
user = await UserService.GetUserAsync(int.Parse(userid));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
user = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
|
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
|
||||||
if (path.EndsWith("/")) { path = path.Substring(0, path.Length - 1); }
|
if (path.EndsWith("/")) { path = path.Substring(0, path.Length - 1); }
|
||||||
if (alias.Path != "")
|
if (alias.Path != "")
|
||||||
|
|
|
@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Components;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.Providers;
|
||||||
|
using Microsoft.AspNetCore.Blazor.Http;
|
||||||
|
|
||||||
namespace Oqtane.Client
|
namespace Oqtane.Client
|
||||||
{
|
{
|
||||||
|
@ -27,6 +29,11 @@ namespace Oqtane.Client
|
||||||
#if WASM
|
#if WASM
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
// register auth services
|
||||||
|
services.AddAuthorizationCore();
|
||||||
|
services.AddScoped<ServerAuthenticationStateProvider>();
|
||||||
|
services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<ServerAuthenticationStateProvider>());
|
||||||
|
|
||||||
// register scoped core services
|
// register scoped core services
|
||||||
services.AddScoped<SiteState>();
|
services.AddScoped<SiteState>();
|
||||||
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
||||||
|
@ -39,6 +46,7 @@ namespace Oqtane.Client
|
||||||
services.AddScoped<IPageModuleService, PageModuleService>();
|
services.AddScoped<IPageModuleService, PageModuleService>();
|
||||||
services.AddScoped<IUserService, UserService>();
|
services.AddScoped<IUserService, UserService>();
|
||||||
|
|
||||||
|
|
||||||
// dynamically register module contexts and repository services
|
// dynamically register module contexts and repository services
|
||||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
foreach (Assembly assembly in assemblies)
|
foreach (Assembly assembly in assemblies)
|
||||||
|
@ -63,6 +71,7 @@ namespace Oqtane.Client
|
||||||
|
|
||||||
public void Configure(IComponentsApplicationBuilder app)
|
public void Configure(IComponentsApplicationBuilder app)
|
||||||
{
|
{
|
||||||
|
WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
|
||||||
app.AddComponent<App>("app");
|
app.AddComponent<App>("app");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,41 +1,34 @@
|
||||||
@using Oqtane.Themes
|
@using Oqtane.Themes
|
||||||
@using Oqtane.Shared
|
@using Oqtane.Services
|
||||||
@using Microsoft.JSInterop
|
@using Oqtane.Providers
|
||||||
@inherits ThemeObjectBase
|
@inherits ThemeObjectBase
|
||||||
@inject IUriHelper UriHelper
|
@inject IUriHelper UriHelper
|
||||||
@inject IJSRuntime jsRuntime
|
@inject IUserService UserService
|
||||||
|
@inject ServerAuthenticationStateProvider AuthStateProvider
|
||||||
|
|
||||||
|
<AuthorizeView>
|
||||||
|
<Authorizing>
|
||||||
|
<text>...</text>
|
||||||
|
</Authorizing>
|
||||||
|
<Authorized>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@LogoutUser">Logout</button>
|
||||||
|
</Authorized>
|
||||||
|
<NotAuthorized>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@LoginUser">Login</button>
|
||||||
|
</NotAuthorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
||||||
<button type="button" class="btn btn-primary" @onclick="@Click">@name</button>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
string name = "";
|
private void LoginUser()
|
||||||
|
|
||||||
protected override async Task OnInitAsync()
|
|
||||||
{
|
{
|
||||||
var interop = new Interop(jsRuntime);
|
UriHelper.NavigateTo(NavigateUrl("login"));
|
||||||
string user = await interop.GetCookie("user");
|
|
||||||
|
|
||||||
if (user == "")
|
|
||||||
{
|
|
||||||
name = "Login";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = "Logout";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Click()
|
private async Task LogoutUser()
|
||||||
{
|
{
|
||||||
if (name == "Login")
|
await UserService.LogoutUserAsync();
|
||||||
{
|
AuthStateProvider.NotifyAuthenticationChanged();
|
||||||
UriHelper.NavigateTo(NavigateUrl("login"));
|
UriHelper.NavigateTo(NavigateUrl(""));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var interop = new Interop(jsRuntime);
|
|
||||||
await interop.SetCookie("user", "", 7);
|
|
||||||
UriHelper.NavigateTo(NavigateUrl(""), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,25 @@
|
||||||
@using Microsoft.AspNetCore.Components.Routing
|
@using Oqtane.Themes
|
||||||
@using Oqtane.Themes
|
|
||||||
@using Oqtane.Shared
|
|
||||||
@using Oqtane.Services;
|
|
||||||
@using Oqtane.Models;
|
|
||||||
@using Microsoft.JSInterop
|
|
||||||
@inject IJSRuntime jsRuntime
|
|
||||||
@inherits ThemeObjectBase
|
@inherits ThemeObjectBase
|
||||||
|
@inject IUriHelper UriHelper
|
||||||
|
|
||||||
|
<AuthorizeView>
|
||||||
|
<Authorizing>
|
||||||
|
<text>...</text>
|
||||||
|
</Authorizing>
|
||||||
|
<Authorized>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@RegisterUser">@context.User.Identity.Name</button>
|
||||||
|
</Authorized>
|
||||||
|
<NotAuthorized>
|
||||||
|
<button type="button" class="btn btn-primary" @onclick="@RegisterUser">Register</button>
|
||||||
|
</NotAuthorized>
|
||||||
|
</AuthorizeView>
|
||||||
|
|
||||||
<NavLink class="btn btn-primary" href="@url">@name</NavLink>
|
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
string name = "";
|
|
||||||
string url = "";
|
|
||||||
|
|
||||||
protected override async Task OnInitAsync()
|
private void RegisterUser()
|
||||||
{
|
{
|
||||||
var interop = new Interop(jsRuntime);
|
UriHelper.NavigateTo(NavigateUrl("register"));
|
||||||
string userid = await interop.GetCookie("user");
|
|
||||||
|
|
||||||
if (userid == "")
|
|
||||||
{
|
|
||||||
name = "Register";
|
|
||||||
url = "register";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PageState.User != null)
|
|
||||||
{
|
|
||||||
name = PageState.User.DisplayName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
|
@ -9,10 +11,14 @@ namespace Oqtane.Controllers
|
||||||
public class UserController : Controller
|
public class UserController : Controller
|
||||||
{
|
{
|
||||||
private readonly IUserRepository users;
|
private readonly IUserRepository users;
|
||||||
|
private readonly UserManager<IdentityUser> identityUserManager;
|
||||||
|
private readonly SignInManager<IdentityUser> identitySignInManager;
|
||||||
|
|
||||||
public UserController(IUserRepository Users)
|
public UserController(IUserRepository Users, UserManager<IdentityUser> IdentityUserManager, SignInManager<IdentityUser> IdentitySignInManager)
|
||||||
{
|
{
|
||||||
users = Users;
|
users = Users;
|
||||||
|
identityUserManager = IdentityUserManager;
|
||||||
|
identitySignInManager = IdentitySignInManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET: api/<controller>
|
// GET: api/<controller>
|
||||||
|
@ -31,10 +37,23 @@ namespace Oqtane.Controllers
|
||||||
|
|
||||||
// POST api/<controller>
|
// POST api/<controller>
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public void Post([FromBody] User user)
|
public async Task Post([FromBody] User user)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
users.AddUser(user);
|
{
|
||||||
|
IdentityUser identityuser = await identityUserManager.FindByNameAsync(user.Username);
|
||||||
|
if (identityuser == null)
|
||||||
|
{
|
||||||
|
identityuser = new IdentityUser();
|
||||||
|
identityuser.UserName = user.Username;
|
||||||
|
identityuser.Email = user.Username;
|
||||||
|
var result = await identityUserManager.CreateAsync(identityuser, user.Password);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
users.AddUser(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT api/<controller>/5
|
// PUT api/<controller>/5
|
||||||
|
@ -42,7 +61,9 @@ namespace Oqtane.Controllers
|
||||||
public void Put(int id, [FromBody] User user)
|
public void Put(int id, [FromBody] User user)
|
||||||
{
|
{
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
|
{
|
||||||
users.UpdateUser(user);
|
users.UpdateUser(user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DELETE api/<controller>/5
|
// DELETE api/<controller>/5
|
||||||
|
@ -51,5 +72,72 @@ namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
users.DeleteUser(id);
|
users.DeleteUser(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/current
|
||||||
|
[HttpGet("current")]
|
||||||
|
public User Current()
|
||||||
|
{
|
||||||
|
User user = null;
|
||||||
|
if (User.Identity.IsAuthenticated)
|
||||||
|
{
|
||||||
|
user = users.GetUser(User.Identity.Name);
|
||||||
|
user.IsAuthenticated = true;
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/login
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<User> Login([FromBody] User user)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
user = users.GetUser(identityuser.UserName);
|
||||||
|
user.IsAuthenticated = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
user = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/logout
|
||||||
|
[HttpPost("logout")]
|
||||||
|
public async Task Logout([FromBody] User user)
|
||||||
|
{
|
||||||
|
await identitySignInManager.SignOutAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/<controller>/current
|
||||||
|
[HttpGet("authenticate")]
|
||||||
|
public User Authenticate()
|
||||||
|
{
|
||||||
|
return new User { Username = User.Identity.Name, IsAuthenticated = User.Identity.IsAuthenticated };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ using DbUp;
|
||||||
using System.Data.SqlClient;
|
using System.Data.SqlClient;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
namespace Oqtane.Filters
|
namespace Oqtane.Filters
|
||||||
{
|
{
|
||||||
|
@ -109,6 +110,7 @@ namespace Oqtane.Filters
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,13 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Remove="Scripts\Identity.sql" />
|
||||||
<None Remove="Scripts\Master.sql" />
|
<None Remove="Scripts\Master.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Scripts\Master.sql" />
|
<Content Include="Scripts\Master.sql" />
|
||||||
|
<EmbeddedResource Include="Scripts\Identity.sql" />
|
||||||
<EmbeddedResource Include="Scripts\Tenant.sql" />
|
<EmbeddedResource Include="Scripts\Tenant.sql" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -38,8 +40,9 @@
|
||||||
<PackageReference Include="dbup" Version="4.2.0" />
|
<PackageReference Include="dbup" Version="4.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Blazor.Server" Version="3.0.0-preview6.19307.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Blazor.Server" Version="3.0.0-preview6.19307.2" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview6.19307.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0-preview6.19307.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0-preview6.19307.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.3" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.0-preview6.19304.10" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.0.0-preview6.19304.10" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -9,6 +9,7 @@ namespace Oqtane.Repository
|
||||||
void AddUser(User User);
|
void AddUser(User User);
|
||||||
void UpdateUser(User User);
|
void UpdateUser(User User);
|
||||||
User GetUser(int UserId);
|
User GetUser(int UserId);
|
||||||
|
User GetUser(string Username);
|
||||||
void DeleteUser(int UserId);
|
void DeleteUser(int UserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class TenantContext : DbContext
|
public class TenantContext : IdentityDbContext<IdentityUser>
|
||||||
{
|
{
|
||||||
public virtual DbSet<Site> Site { get; set; }
|
public virtual DbSet<Site> Site { get; set; }
|
||||||
public virtual DbSet<Page> Page { get; set; }
|
public virtual DbSet<Page> Page { get; set; }
|
||||||
|
|
|
@ -28,6 +28,10 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
aliasname += "/" + segments[1];
|
aliasname += "/" + segments[1];
|
||||||
}
|
}
|
||||||
|
if (aliasname.EndsWith("/"))
|
||||||
|
{
|
||||||
|
aliasname = aliasname.Substring(0, aliasname.Length - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tenant GetTenant()
|
public Tenant GetTenant()
|
||||||
|
|
|
@ -65,6 +65,19 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public User GetUser(string Username)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
User user = db.User.Where(item => item.Username == Username).FirstOrDefault();
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteUser(int userId)
|
public void DeleteUser(int userId)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
190
Oqtane.Server/Scripts/Identity.sql
Normal file
190
Oqtane.Server/Scripts/Identity.sql
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
CREATE TABLE [dbo].[AspNetRoleClaims](
|
||||||
|
[Id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[RoleId] [nvarchar](450) NOT NULL,
|
||||||
|
[ClaimType] [nvarchar](max) NULL,
|
||||||
|
[ClaimValue] [nvarchar](max) NULL,
|
||||||
|
CONSTRAINT [PK_AspNetRoleClaims] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[Id] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetRoles](
|
||||||
|
[Id] [nvarchar](450) NOT NULL,
|
||||||
|
[Name] [nvarchar](256) NULL,
|
||||||
|
[NormalizedName] [nvarchar](256) NULL,
|
||||||
|
[ConcurrencyStamp] [nvarchar](max) NULL,
|
||||||
|
CONSTRAINT [PK_AspNetRoles] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[Id] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetUserClaims](
|
||||||
|
[Id] [int] IDENTITY(1,1) NOT NULL,
|
||||||
|
[UserId] [nvarchar](450) NOT NULL,
|
||||||
|
[ClaimType] [nvarchar](max) NULL,
|
||||||
|
[ClaimValue] [nvarchar](max) NULL,
|
||||||
|
CONSTRAINT [PK_AspNetUserClaims] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[Id] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetUserLogins](
|
||||||
|
[LoginProvider] [nvarchar](128) NOT NULL,
|
||||||
|
[ProviderKey] [nvarchar](128) NOT NULL,
|
||||||
|
[ProviderDisplayName] [nvarchar](max) NULL,
|
||||||
|
[UserId] [nvarchar](450) NOT NULL,
|
||||||
|
CONSTRAINT [PK_AspNetUserLogins] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[LoginProvider] ASC,
|
||||||
|
[ProviderKey] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetUserRoles](
|
||||||
|
[UserId] [nvarchar](450) NOT NULL,
|
||||||
|
[RoleId] [nvarchar](450) NOT NULL,
|
||||||
|
CONSTRAINT [PK_AspNetUserRoles] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[UserId] ASC,
|
||||||
|
[RoleId] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetUsers](
|
||||||
|
[Id] [nvarchar](450) NOT NULL,
|
||||||
|
[UserName] [nvarchar](256) NULL,
|
||||||
|
[NormalizedUserName] [nvarchar](256) NULL,
|
||||||
|
[Email] [nvarchar](256) NULL,
|
||||||
|
[NormalizedEmail] [nvarchar](256) NULL,
|
||||||
|
[EmailConfirmed] [bit] NOT NULL,
|
||||||
|
[PasswordHash] [nvarchar](max) NULL,
|
||||||
|
[SecurityStamp] [nvarchar](max) NULL,
|
||||||
|
[ConcurrencyStamp] [nvarchar](max) NULL,
|
||||||
|
[PhoneNumber] [nvarchar](max) NULL,
|
||||||
|
[PhoneNumberConfirmed] [bit] NOT NULL,
|
||||||
|
[TwoFactorEnabled] [bit] NOT NULL,
|
||||||
|
[LockoutEnd] [datetimeoffset](7) NULL,
|
||||||
|
[LockoutEnabled] [bit] NOT NULL,
|
||||||
|
[AccessFailedCount] [int] NOT NULL,
|
||||||
|
CONSTRAINT [PK_AspNetUsers] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[Id] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE [dbo].[AspNetUserTokens](
|
||||||
|
[UserId] [nvarchar](450) NOT NULL,
|
||||||
|
[LoginProvider] [nvarchar](128) NOT NULL,
|
||||||
|
[Name] [nvarchar](128) NOT NULL,
|
||||||
|
[Value] [nvarchar](max) NULL,
|
||||||
|
CONSTRAINT [PK_AspNetUserTokens] PRIMARY KEY CLUSTERED
|
||||||
|
(
|
||||||
|
[UserId] ASC,
|
||||||
|
[LoginProvider] ASC,
|
||||||
|
[Name] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_AspNetRoleClaims_RoleId] ON [dbo].[AspNetRoleClaims]
|
||||||
|
(
|
||||||
|
[RoleId] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE UNIQUE NONCLUSTERED INDEX [RoleNameIndex] ON [dbo].[AspNetRoles]
|
||||||
|
(
|
||||||
|
[NormalizedName] ASC
|
||||||
|
)
|
||||||
|
WHERE ([NormalizedName] IS NOT NULL)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_AspNetUserClaims_UserId] ON [dbo].[AspNetUserClaims]
|
||||||
|
(
|
||||||
|
[UserId] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_AspNetUserLogins_UserId] ON [dbo].[AspNetUserLogins]
|
||||||
|
(
|
||||||
|
[UserId] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [IX_AspNetUserRoles_RoleId] ON [dbo].[AspNetUserRoles]
|
||||||
|
(
|
||||||
|
[RoleId] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE NONCLUSTERED INDEX [EmailIndex] ON [dbo].[AspNetUsers]
|
||||||
|
(
|
||||||
|
[NormalizedEmail] ASC
|
||||||
|
) ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE UNIQUE NONCLUSTERED INDEX [UserNameIndex] ON [dbo].[AspNetUsers]
|
||||||
|
(
|
||||||
|
[NormalizedUserName] ASC
|
||||||
|
)
|
||||||
|
WHERE ([NormalizedUserName] IS NOT NULL)
|
||||||
|
ON [PRIMARY]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetRoleClaims] WITH CHECK ADD CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId] FOREIGN KEY([RoleId])
|
||||||
|
REFERENCES [dbo].[AspNetRoles] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetRoleClaims] CHECK CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserClaims] WITH CHECK ADD CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId] FOREIGN KEY([UserId])
|
||||||
|
REFERENCES [dbo].[AspNetUsers] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserClaims] CHECK CONSTRAINT [FK_AspNetUserClaims_AspNetUsers_UserId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserLogins] WITH CHECK ADD CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId] FOREIGN KEY([UserId])
|
||||||
|
REFERENCES [dbo].[AspNetUsers] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserLogins] CHECK CONSTRAINT [FK_AspNetUserLogins_AspNetUsers_UserId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserRoles] WITH CHECK ADD CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId] FOREIGN KEY([RoleId])
|
||||||
|
REFERENCES [dbo].[AspNetRoles] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_AspNetUserRoles_AspNetRoles_RoleId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserRoles] WITH CHECK ADD CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId] FOREIGN KEY([UserId])
|
||||||
|
REFERENCES [dbo].[AspNetUsers] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_AspNetUserRoles_AspNetUsers_UserId]
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserTokens] WITH CHECK ADD CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId] FOREIGN KEY([UserId])
|
||||||
|
REFERENCES [dbo].[AspNetUsers] ([Id])
|
||||||
|
ON DELETE CASCADE
|
||||||
|
GO
|
||||||
|
|
||||||
|
ALTER TABLE [dbo].[AspNetUserTokens] CHECK CONSTRAINT [FK_AspNetUserTokens_AspNetUsers_UserId]
|
||||||
|
GO
|
|
@ -313,21 +313,4 @@ GO
|
||||||
SET IDENTITY_INSERT [dbo].[HtmlText] OFF
|
SET IDENTITY_INSERT [dbo].[HtmlText] OFF
|
||||||
GO
|
GO
|
||||||
|
|
||||||
SET IDENTITY_INSERT [dbo].[User] ON
|
|
||||||
GO
|
|
||||||
INSERT [dbo].[User] ([UserId], [Username], [DisplayName], [Roles], [IsSuperUser])
|
|
||||||
VALUES (1, N'host', N'Host', N'', 1)
|
|
||||||
GO
|
|
||||||
INSERT [dbo].[User] ([UserId], [Username], [DisplayName], [Roles], [IsSuperUser])
|
|
||||||
VALUES (2, N'admin', N'Administrator', N'Administrators;', 0)
|
|
||||||
GO
|
|
||||||
INSERT [dbo].[User] ([UserId], [Username], [DisplayName], [Roles], [IsSuperUser])
|
|
||||||
VALUES (3, N'editor', N'Editor', N'Editors;', 0)
|
|
||||||
GO
|
|
||||||
INSERT [dbo].[User] ([UserId], [Username], [DisplayName], [Roles], [IsSuperUser])
|
|
||||||
VALUES (4, N'member', N'Member', N'Members;', 0)
|
|
||||||
GO
|
|
||||||
SET IDENTITY_INSERT [dbo].[User] OFF
|
|
||||||
GO
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,10 @@ using System.Net.Http;
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using Oqtane.Client;
|
using Oqtane.Client;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Oqtane.Providers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
|
||||||
namespace Oqtane.Server
|
namespace Oqtane.Server
|
||||||
{
|
{
|
||||||
|
@ -58,6 +62,11 @@ namespace Oqtane.Server
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register auth services
|
||||||
|
services.AddAuthorizationCore();
|
||||||
|
services.AddScoped<ServerAuthenticationStateProvider>();
|
||||||
|
services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<ServerAuthenticationStateProvider>());
|
||||||
|
|
||||||
// register scoped core services
|
// register scoped core services
|
||||||
services.AddScoped<SiteState>();
|
services.AddScoped<SiteState>();
|
||||||
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
|
||||||
|
@ -99,6 +108,38 @@ namespace Oqtane.Server
|
||||||
));
|
));
|
||||||
services.AddDbContext<TenantContext>(options => { });
|
services.AddDbContext<TenantContext>(options => { });
|
||||||
|
|
||||||
|
services.AddIdentity<IdentityUser, IdentityRole>()
|
||||||
|
.AddEntityFrameworkStores<TenantContext>()
|
||||||
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
|
services.Configure<IdentityOptions>(options =>
|
||||||
|
{
|
||||||
|
// Password settings
|
||||||
|
options.Password.RequireDigit = false;
|
||||||
|
options.Password.RequiredLength = 6;
|
||||||
|
options.Password.RequireNonAlphanumeric = false;
|
||||||
|
options.Password.RequireUppercase = false;
|
||||||
|
options.Password.RequireLowercase = false;
|
||||||
|
|
||||||
|
// Lockout settings
|
||||||
|
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
|
||||||
|
options.Lockout.MaxFailedAccessAttempts = 10;
|
||||||
|
options.Lockout.AllowedForNewUsers = true;
|
||||||
|
|
||||||
|
// User settings
|
||||||
|
options.User.RequireUniqueEmail = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.ConfigureApplicationCookie(options =>
|
||||||
|
{
|
||||||
|
options.Cookie.HttpOnly = false;
|
||||||
|
options.Events.OnRedirectToLogin = context =>
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
services.AddMemoryCache();
|
services.AddMemoryCache();
|
||||||
|
|
||||||
services.AddMvc().AddNewtonsoftJson();
|
services.AddMvc().AddNewtonsoftJson();
|
||||||
|
@ -177,6 +218,8 @@ namespace Oqtane.Server
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
|
@ -201,6 +244,38 @@ namespace Oqtane.Server
|
||||||
));
|
));
|
||||||
services.AddDbContext<TenantContext>(options => { });
|
services.AddDbContext<TenantContext>(options => { });
|
||||||
|
|
||||||
|
services.AddIdentity<IdentityUser, IdentityRole>()
|
||||||
|
.AddEntityFrameworkStores<TenantContext>()
|
||||||
|
.AddDefaultTokenProviders();
|
||||||
|
|
||||||
|
services.Configure<IdentityOptions>(options =>
|
||||||
|
{
|
||||||
|
// Password settings
|
||||||
|
options.Password.RequireDigit = false;
|
||||||
|
options.Password.RequiredLength = 6;
|
||||||
|
options.Password.RequireNonAlphanumeric = false;
|
||||||
|
options.Password.RequireUppercase = false;
|
||||||
|
options.Password.RequireLowercase = false;
|
||||||
|
|
||||||
|
// Lockout settings
|
||||||
|
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
|
||||||
|
options.Lockout.MaxFailedAccessAttempts = 10;
|
||||||
|
options.Lockout.AllowedForNewUsers = true;
|
||||||
|
|
||||||
|
// User settings
|
||||||
|
options.User.RequireUniqueEmail = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.ConfigureApplicationCookie(options =>
|
||||||
|
{
|
||||||
|
options.Cookie.HttpOnly = false;
|
||||||
|
options.Events.OnRedirectToLogin = context =>
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
services.AddMemoryCache();
|
services.AddMemoryCache();
|
||||||
|
|
||||||
services.AddMvc().AddNewtonsoftJson();
|
services.AddMvc().AddNewtonsoftJson();
|
||||||
|
@ -281,6 +356,8 @@ namespace Oqtane.Server
|
||||||
app.UseClientSideBlazorFiles<Client.Startup>();
|
app.UseClientSideBlazorFiles<Client.Startup>();
|
||||||
|
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints =>
|
app.UseEndpoints(endpoints =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,5 +9,10 @@ namespace Oqtane.Models
|
||||||
public string DisplayName { get; set; }
|
public string DisplayName { get; set; }
|
||||||
public string Roles { get; set; }
|
public string Roles { get; set; }
|
||||||
public bool IsSuperUser { get; set; }
|
public bool IsSuperUser { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string Password { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public bool IsAuthenticated { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user