Integrated AuthenticationStateProvider using .NET Core Identity
This commit is contained in:
		@ -1,9 +1,11 @@
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Oqtane.Client.Shared
 | 
			
		||||
 | 
			
		||||
<CascadingValue Value="@PageState">
 | 
			
		||||
    <SiteRouter OnStateChange="@ChangeState" />
 | 
			
		||||
</CascadingValue>
 | 
			
		||||
<CascadingAuthenticationState>
 | 
			
		||||
    <CascadingValue Value="@PageState">
 | 
			
		||||
        <SiteRouter OnStateChange="@ChangeState" />
 | 
			
		||||
    </CascadingValue>
 | 
			
		||||
</CascadingAuthenticationState>
 | 
			
		||||
 | 
			
		||||
@code {
 | 
			
		||||
    private PageState PageState { get; set; }
 | 
			
		||||
 | 
			
		||||
@ -1,45 +1,56 @@
 | 
			
		||||
@using Microsoft.AspNetCore.Components.Routing
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Oqtane.Modules
 | 
			
		||||
@using Microsoft.JSInterop
 | 
			
		||||
@using Oqtane.Models
 | 
			
		||||
@using Oqtane.Services
 | 
			
		||||
@using Oqtane.Client.Modules.Controls
 | 
			
		||||
@using Oqtane.Providers
 | 
			
		||||
@inherits ModuleBase
 | 
			
		||||
@inject IUriHelper UriHelper
 | 
			
		||||
@inject IJSRuntime jsRuntime
 | 
			
		||||
@inject IUserService  UserService
 | 
			
		||||
@inject IUserService UserService
 | 
			
		||||
@inject ServerAuthenticationStateProvider AuthStateProvider
 | 
			
		||||
 | 
			
		||||
<div class="container">
 | 
			
		||||
    @((MarkupString)Message)
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
        <label for="Username" class="control-label">Username: </label>
 | 
			
		||||
        <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>
 | 
			
		||||
<AuthorizeView>
 | 
			
		||||
    <Authorizing>
 | 
			
		||||
        <text>...</text>
 | 
			
		||||
    </Authorizing>
 | 
			
		||||
    <Authorized>
 | 
			
		||||
        You are already logged in
 | 
			
		||||
    </Authorized>
 | 
			
		||||
    <NotAuthorized>
 | 
			
		||||
        <div class="container">
 | 
			
		||||
            @((MarkupString)Message)
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
                <label for="Username" class="control-label">Username: </label>
 | 
			
		||||
                <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 {
 | 
			
		||||
    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 Password { get; set; } = "";
 | 
			
		||||
 | 
			
		||||
    private async Task Login()
 | 
			
		||||
    {
 | 
			
		||||
        List<User> users = await UserService.GetUsersAsync();
 | 
			
		||||
        User user = users.Where(item => item.Username == Username).FirstOrDefault();
 | 
			
		||||
        User user = new User();
 | 
			
		||||
        user.Username = Username;
 | 
			
		||||
        user.Password = Password;
 | 
			
		||||
        user = await UserService.LoginUserAsync(user);
 | 
			
		||||
        if (user != null)
 | 
			
		||||
        {
 | 
			
		||||
            var interop = new Interop(jsRuntime);
 | 
			
		||||
            await interop.SetCookie("user", user.UserId.ToString(), 7);
 | 
			
		||||
            UriHelper.NavigateTo(NavigateUrl(""), true);
 | 
			
		||||
            AuthStateProvider.NotifyAuthenticationChanged();
 | 
			
		||||
            UriHelper.NavigateTo(NavigateUrl(""));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,10 @@
 | 
			
		||||
@using Microsoft.AspNetCore.Components.Routing
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Oqtane.Modules
 | 
			
		||||
@using Microsoft.JSInterop
 | 
			
		||||
@using Oqtane.Client.Modules.Controls
 | 
			
		||||
@using Oqtane.Models
 | 
			
		||||
@using Oqtane.Services
 | 
			
		||||
@inherits ModuleBase
 | 
			
		||||
@inject IUriHelper UriHelper
 | 
			
		||||
@inject IJSRuntime jsRuntime
 | 
			
		||||
 | 
			
		||||
@inject IUserService UserService
 | 
			
		||||
 | 
			
		||||
<div class="container">
 | 
			
		||||
    <div class="form-group">
 | 
			
		||||
@ -17,13 +15,25 @@
 | 
			
		||||
        <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">Register</button>
 | 
			
		||||
    <button type="button" class="btn btn-primary" @onclick="@RegisterUser">Register</button>
 | 
			
		||||
    <NavLink class="btn btn-secondary" href="/">Cancel</NavLink>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@code {
 | 
			
		||||
    public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
 | 
			
		||||
public override SecurityAccessLevelEnum SecurityAccessLevel { get { return SecurityAccessLevelEnum.Anonymous; } }
 | 
			
		||||
 | 
			
		||||
    public string Username { get; set; } = "";
 | 
			
		||||
    public string Password { get; set; } = "";
 | 
			
		||||
public string Username { 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<User> GetCurrentUserAsync();
 | 
			
		||||
 | 
			
		||||
        Task<User> LoginUserAsync(User user);
 | 
			
		||||
 | 
			
		||||
        Task LogoutUserAsync();
 | 
			
		||||
 | 
			
		||||
        bool IsAuthorized(User user, string accesscontrollist);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,13 @@ namespace Oqtane.Services
 | 
			
		||||
    {
 | 
			
		||||
        private readonly HttpClient http;
 | 
			
		||||
        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.sitestate = sitestate;
 | 
			
		||||
            this.urihelper = urihelper;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private string apiurl
 | 
			
		||||
@ -35,7 +37,7 @@ namespace Oqtane.Services
 | 
			
		||||
        {
 | 
			
		||||
            List<User> users = await http.GetJsonAsync<List<User>>(apiurl);
 | 
			
		||||
            return users.Where(item => item.UserId == UserId).FirstOrDefault();
 | 
			
		||||
    }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task AddUserAsync(User user)
 | 
			
		||||
        {
 | 
			
		||||
@ -51,6 +53,22 @@ namespace Oqtane.Services
 | 
			
		||||
            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
 | 
			
		||||
        public bool IsAuthorized(User user, string accesscontrollist)
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Microsoft.JSInterop
 | 
			
		||||
@using Microsoft.AspNetCore.Components.Routing
 | 
			
		||||
@inject AuthenticationStateProvider AuthenticationStateProvider
 | 
			
		||||
@inject SiteState SiteState
 | 
			
		||||
@inject IUriHelper UriHelper
 | 
			
		||||
@inject INavigationInterception NavigationInterception
 | 
			
		||||
@ -106,15 +107,13 @@ private async Task Refresh()
 | 
			
		||||
    }
 | 
			
		||||
    if (site != null || reload == true)
 | 
			
		||||
    {
 | 
			
		||||
        var interop = new Interop(jsRuntime);
 | 
			
		||||
        string userid = await interop.GetCookie("user");
 | 
			
		||||
 | 
			
		||||
        user = null;
 | 
			
		||||
        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
 | 
			
		||||
@ -122,23 +121,6 @@ private async Task Refresh()
 | 
			
		||||
            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);
 | 
			
		||||
        if (path.EndsWith("/")) { path = path.Substring(0, path.Length - 1); }
 | 
			
		||||
        if (alias.Path != "")
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Components;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Oqtane.Modules;
 | 
			
		||||
using Oqtane.Shared;
 | 
			
		||||
using Oqtane.Providers;
 | 
			
		||||
using Microsoft.AspNetCore.Blazor.Http;
 | 
			
		||||
 | 
			
		||||
namespace Oqtane.Client
 | 
			
		||||
{
 | 
			
		||||
@ -27,6 +29,11 @@ namespace Oqtane.Client
 | 
			
		||||
#if WASM
 | 
			
		||||
        public void ConfigureServices(IServiceCollection services)
 | 
			
		||||
        {
 | 
			
		||||
            // register auth services
 | 
			
		||||
            services.AddAuthorizationCore();
 | 
			
		||||
            services.AddScoped<ServerAuthenticationStateProvider>();
 | 
			
		||||
            services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<ServerAuthenticationStateProvider>());
 | 
			
		||||
 | 
			
		||||
            // register scoped core services
 | 
			
		||||
            services.AddScoped<SiteState>();
 | 
			
		||||
            services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
 | 
			
		||||
@ -39,6 +46,7 @@ namespace Oqtane.Client
 | 
			
		||||
            services.AddScoped<IPageModuleService, PageModuleService>();
 | 
			
		||||
            services.AddScoped<IUserService, UserService>();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // dynamically register module contexts and repository services
 | 
			
		||||
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
 | 
			
		||||
            foreach (Assembly assembly in assemblies)
 | 
			
		||||
@ -63,6 +71,7 @@ namespace Oqtane.Client
 | 
			
		||||
 | 
			
		||||
        public void Configure(IComponentsApplicationBuilder app)
 | 
			
		||||
        {
 | 
			
		||||
            WebAssemblyHttpMessageHandler.DefaultCredentials = FetchCredentialsOption.Include;
 | 
			
		||||
            app.AddComponent<App>("app");
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,41 +1,34 @@
 | 
			
		||||
@using Oqtane.Themes
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Microsoft.JSInterop
 | 
			
		||||
@using  Oqtane.Services
 | 
			
		||||
@using Oqtane.Providers
 | 
			
		||||
@inherits ThemeObjectBase
 | 
			
		||||
@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 {
 | 
			
		||||
    string name = "";
 | 
			
		||||
 | 
			
		||||
    protected override async Task OnInitAsync()
 | 
			
		||||
    private void LoginUser()
 | 
			
		||||
    {
 | 
			
		||||
        var interop = new Interop(jsRuntime);
 | 
			
		||||
        string user = await interop.GetCookie("user");
 | 
			
		||||
 | 
			
		||||
        if (user == "")
 | 
			
		||||
        {
 | 
			
		||||
            name = "Login";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            name = "Logout";
 | 
			
		||||
        }
 | 
			
		||||
        UriHelper.NavigateTo(NavigateUrl("login"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async Task Click()
 | 
			
		||||
    private async Task LogoutUser()
 | 
			
		||||
    {
 | 
			
		||||
        if (name == "Login")
 | 
			
		||||
        {
 | 
			
		||||
            UriHelper.NavigateTo(NavigateUrl("login"));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            var interop = new Interop(jsRuntime);
 | 
			
		||||
            await interop.SetCookie("user", "", 7);
 | 
			
		||||
            UriHelper.NavigateTo(NavigateUrl(""), true);
 | 
			
		||||
        }
 | 
			
		||||
        await UserService.LogoutUserAsync();
 | 
			
		||||
        AuthStateProvider.NotifyAuthenticationChanged();
 | 
			
		||||
        UriHelper.NavigateTo(NavigateUrl(""));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,35 +1,25 @@
 | 
			
		||||
@using Microsoft.AspNetCore.Components.Routing
 | 
			
		||||
@using Oqtane.Themes
 | 
			
		||||
@using Oqtane.Shared
 | 
			
		||||
@using Oqtane.Services;
 | 
			
		||||
@using Oqtane.Models;
 | 
			
		||||
@using Microsoft.JSInterop
 | 
			
		||||
@inject IJSRuntime jsRuntime
 | 
			
		||||
@using Oqtane.Themes
 | 
			
		||||
@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 {
 | 
			
		||||
    string name = "";
 | 
			
		||||
    string url = "";
 | 
			
		||||
 | 
			
		||||
    protected override async Task OnInitAsync()
 | 
			
		||||
    private void RegisterUser()
 | 
			
		||||
    {
 | 
			
		||||
        var interop = new Interop(jsRuntime);
 | 
			
		||||
        string userid = await interop.GetCookie("user");
 | 
			
		||||
 | 
			
		||||
        if (userid == "")
 | 
			
		||||
        {
 | 
			
		||||
            name = "Register";
 | 
			
		||||
            url = "register";
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (PageState.User != null)
 | 
			
		||||
            {
 | 
			
		||||
                name = PageState.User.DisplayName;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        UriHelper.NavigateTo(NavigateUrl("register"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,8 @@
 | 
			
		||||
using Microsoft.AspNetCore.Mvc;
 | 
			
		||||
using Oqtane.Repository;
 | 
			
		||||
using Oqtane.Models;
 | 
			
		||||
using Microsoft.AspNetCore.Identity;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Oqtane.Controllers
 | 
			
		||||
{
 | 
			
		||||
@ -9,10 +11,14 @@ namespace Oqtane.Controllers
 | 
			
		||||
    public class UserController : Controller
 | 
			
		||||
    {
 | 
			
		||||
        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;
 | 
			
		||||
            identityUserManager = IdentityUserManager;
 | 
			
		||||
            identitySignInManager = IdentitySignInManager;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // GET: api/<controller>
 | 
			
		||||
@ -31,10 +37,23 @@ namespace Oqtane.Controllers
 | 
			
		||||
 | 
			
		||||
        // POST api/<controller>
 | 
			
		||||
        [HttpPost]
 | 
			
		||||
        public void Post([FromBody] User user)
 | 
			
		||||
        public async Task Post([FromBody] User user)
 | 
			
		||||
        {
 | 
			
		||||
            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
 | 
			
		||||
@ -42,7 +61,9 @@ namespace Oqtane.Controllers
 | 
			
		||||
        public void Put(int id, [FromBody] User user)
 | 
			
		||||
        {
 | 
			
		||||
            if (ModelState.IsValid)
 | 
			
		||||
            {
 | 
			
		||||
                users.UpdateUser(user);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // DELETE api/<controller>/5
 | 
			
		||||
@ -51,5 +72,72 @@ namespace Oqtane.Controllers
 | 
			
		||||
        {
 | 
			
		||||
            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.Threading;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Microsoft.AspNetCore.Identity;
 | 
			
		||||
 | 
			
		||||
namespace Oqtane.Filters
 | 
			
		||||
{
 | 
			
		||||
@ -109,6 +110,7 @@ namespace Oqtane.Filters
 | 
			
		||||
                    throw new Exception();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return next;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -26,11 +26,13 @@
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Remove="Scripts\Identity.sql" />
 | 
			
		||||
    <None Remove="Scripts\Master.sql" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <Content Include="Scripts\Master.sql" />
 | 
			
		||||
    <EmbeddedResource Include="Scripts\Identity.sql" />
 | 
			
		||||
    <EmbeddedResource Include="Scripts\Tenant.sql" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
@ -38,8 +40,9 @@
 | 
			
		||||
    <PackageReference Include="dbup" Version="4.2.0" />
 | 
			
		||||
    <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.EntityFrameworkCore" Version="2.2.3" />
 | 
			
		||||
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.2.3" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0-preview6.19307.2" />
 | 
			
		||||
    <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>
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ namespace Oqtane.Repository
 | 
			
		||||
        void AddUser(User User);
 | 
			
		||||
        void UpdateUser(User User);
 | 
			
		||||
        User GetUser(int UserId);
 | 
			
		||||
        User GetUser(string Username);
 | 
			
		||||
        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 System;
 | 
			
		||||
 | 
			
		||||
namespace Oqtane.Repository
 | 
			
		||||
{
 | 
			
		||||
    public class TenantContext : DbContext
 | 
			
		||||
    public class TenantContext : IdentityDbContext<IdentityUser>
 | 
			
		||||
    {
 | 
			
		||||
        public virtual DbSet<Site> Site { get; set; }
 | 
			
		||||
        public virtual DbSet<Page> Page { get; set; }
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,10 @@ namespace Oqtane.Repository
 | 
			
		||||
            {
 | 
			
		||||
                aliasname += "/" + segments[1];
 | 
			
		||||
            }
 | 
			
		||||
            if (aliasname.EndsWith("/"))
 | 
			
		||||
            {
 | 
			
		||||
                aliasname = aliasname.Substring(0, aliasname.Length - 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        {
 | 
			
		||||
            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 
 | 
			
		||||
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 Oqtane.Client;
 | 
			
		||||
using Oqtane.Shared;
 | 
			
		||||
using Microsoft.AspNetCore.Identity;
 | 
			
		||||
using Oqtane.Providers;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Authentication.Cookies;
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
            services.AddScoped<SiteState>();
 | 
			
		||||
            services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
 | 
			
		||||
@ -99,6 +108,38 @@ namespace Oqtane.Server
 | 
			
		||||
                ));
 | 
			
		||||
            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.AddMvc().AddNewtonsoftJson();
 | 
			
		||||
@ -177,6 +218,8 @@ namespace Oqtane.Server
 | 
			
		||||
            app.UseStaticFiles();
 | 
			
		||||
 | 
			
		||||
            app.UseRouting();
 | 
			
		||||
            app.UseAuthentication();
 | 
			
		||||
            app.UseAuthorization();
 | 
			
		||||
 | 
			
		||||
            app.UseEndpoints(endpoints =>
 | 
			
		||||
            {
 | 
			
		||||
@ -201,6 +244,38 @@ namespace Oqtane.Server
 | 
			
		||||
                ));
 | 
			
		||||
            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.AddMvc().AddNewtonsoftJson();
 | 
			
		||||
@ -281,6 +356,8 @@ namespace Oqtane.Server
 | 
			
		||||
            app.UseClientSideBlazorFiles<Client.Startup>();
 | 
			
		||||
 | 
			
		||||
            app.UseRouting();
 | 
			
		||||
            app.UseAuthentication();
 | 
			
		||||
            app.UseAuthorization();
 | 
			
		||||
 | 
			
		||||
            app.UseEndpoints(endpoints =>
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -9,5 +9,10 @@ namespace Oqtane.Models
 | 
			
		||||
        public string DisplayName { get; set; }
 | 
			
		||||
        public string Roles { get; set; }
 | 
			
		||||
        public bool IsSuperUser { get; set; }
 | 
			
		||||
 | 
			
		||||
        [NotMapped]
 | 
			
		||||
        public string Password { get; set; }
 | 
			
		||||
        [NotMapped]
 | 
			
		||||
        public bool IsAuthenticated { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user