Permission-based authorization utilizing Policies
This commit is contained in:
@ -9,14 +9,15 @@ namespace Oqtane.Models
|
||||
public int ModuleId { get; set; }
|
||||
public int SiteId { get; set; }
|
||||
public string ModuleDefinitionName { get; set; }
|
||||
public string ViewPermissions { get; set; }
|
||||
public string EditPermissions { get; set; }
|
||||
|
||||
public string CreatedBy { get; set; }
|
||||
public DateTime CreatedOn { get; set; }
|
||||
public string ModifiedBy { get; set; }
|
||||
public DateTime ModifiedOn { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public string Permissions { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public int PageModuleId { get; set; }
|
||||
[NotMapped]
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Oqtane.Models
|
||||
{
|
||||
@ -14,13 +15,15 @@ namespace Oqtane.Models
|
||||
public string LayoutType { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public string Panes { get; set; }
|
||||
public string ViewPermissions { get; set; }
|
||||
public string EditPermissions { get; set; }
|
||||
public bool IsNavigation { get; set; }
|
||||
|
||||
public string CreatedBy { get; set; }
|
||||
public DateTime CreatedOn { get; set; }
|
||||
public string ModifiedBy { get; set; }
|
||||
public DateTime ModifiedOn { get; set; }
|
||||
|
||||
|
||||
[NotMapped]
|
||||
public string Permissions { get; set; }
|
||||
}
|
||||
}
|
||||
|
23
Oqtane.Shared/Models/Permission.cs
Normal file
23
Oqtane.Shared/Models/Permission.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Oqtane.Models
|
||||
{
|
||||
public class Permission : IAuditable
|
||||
{
|
||||
public int PermissionId { get; set; }
|
||||
public int SiteId { get; set; }
|
||||
public string EntityName { get; set; }
|
||||
public int EntityId { get; set; }
|
||||
public string PermissionName { get; set; }
|
||||
public int? RoleId { get; set; }
|
||||
public int? UserId { get; set; }
|
||||
public bool IsAuthorized { get; set; }
|
||||
|
||||
public string CreatedBy { get; set; }
|
||||
public DateTime CreatedOn { get; set; }
|
||||
public string ModifiedBy { get; set; }
|
||||
public DateTime ModifiedOn { get; set; }
|
||||
|
||||
public Role Role { get; set; }
|
||||
}
|
||||
}
|
@ -8,7 +8,8 @@ namespace Oqtane.Models
|
||||
public int UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public bool IsSuperUser { get; set; }
|
||||
public string Email { get; set; }
|
||||
public bool IsHost { get; set; }
|
||||
[NotMapped]
|
||||
public int SiteId { get; set; }
|
||||
[NotMapped]
|
||||
|
103
Oqtane.Shared/Security/UserSecurity.cs
Normal file
103
Oqtane.Shared/Security/UserSecurity.cs
Normal file
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Security
|
||||
{
|
||||
public class UserSecurity
|
||||
{
|
||||
// permission collections are stored in format {permissionname1:permissions}{permissionname2:permissions}...
|
||||
public static string GetPermissions(string PermissionName, string Permissions)
|
||||
{
|
||||
string permissions = "";
|
||||
foreach(string permission in Permissions.Split(new char[] { '{' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
if (permission.StartsWith(PermissionName + ":"))
|
||||
{
|
||||
permissions = permission.Replace(PermissionName + ":", "").Replace("}", "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
|
||||
public static string SetPermissions(string PermissionName, string Permissions)
|
||||
{
|
||||
return "{" + PermissionName + ":" + Permissions + "}";
|
||||
}
|
||||
|
||||
// permissions are stored in the format "!rolename1;![userid1];rolename2;rolename3;[userid2];[userid3]" where "!" designates Deny permissions
|
||||
public static bool IsAuthorized(User User, string PermissionName, string Permissions)
|
||||
{
|
||||
Permissions = GetPermissions(PermissionName, Permissions);
|
||||
if (User == null)
|
||||
{
|
||||
return IsAuthorized(-1, "", Permissions); // user is not authenticated but may have access to resource
|
||||
}
|
||||
else
|
||||
{
|
||||
return IsAuthorized(User.UserId, User.Roles, Permissions);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAuthorized(int UserId, string Roles, string Permissions)
|
||||
{
|
||||
bool IsAuthorized = false;
|
||||
|
||||
if (Permissions != null)
|
||||
{
|
||||
foreach (string permission in Permissions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
bool? allowed = VerifyPermission(UserId, Roles, permission);
|
||||
if (allowed.HasValue)
|
||||
{
|
||||
IsAuthorized = allowed.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IsAuthorized;
|
||||
}
|
||||
|
||||
private static bool? VerifyPermission(int UserId, string Roles, string Permission)
|
||||
{
|
||||
bool? allowed = null;
|
||||
//permissions strings are encoded with deny permissions at the beginning and grant permissions at the end for optimal performance
|
||||
if (!String.IsNullOrEmpty(Permission))
|
||||
{
|
||||
// deny permission
|
||||
if (Permission.StartsWith("!"))
|
||||
{
|
||||
string denyRole = Permission.Replace("!", "");
|
||||
if (denyRole == Constants.AllUsersRole || IsAllowed(UserId, Roles, denyRole))
|
||||
{
|
||||
allowed = false;
|
||||
}
|
||||
}
|
||||
else // grant permission
|
||||
{
|
||||
if (Permission == Constants.AllUsersRole || IsAllowed(UserId, Roles, Permission))
|
||||
{
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
private static bool IsAllowed(int UserId, string Roles, string Permission)
|
||||
{
|
||||
if ("[" + UserId + "]" == Permission)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Roles != null)
|
||||
{
|
||||
return Roles.IndexOf(";" + Permission + ";") != -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
23
Oqtane.Shared/Shared/Constants.cs
Normal file
23
Oqtane.Shared/Shared/Constants.cs
Normal file
@ -0,0 +1,23 @@
|
||||
namespace Oqtane.Shared
|
||||
{
|
||||
public class Constants
|
||||
{
|
||||
public const string DefaultPage = "Oqtane.Client.Shared.Theme, Oqtane.Client";
|
||||
public const string DefaultContainer = "Oqtane.Client.Shared.Container, Oqtane.Client";
|
||||
public const string DefaultAdminContainer = "Oqtane.Client.Themes.AdminContainer, Oqtane.Client";
|
||||
public const string DefaultSettingsControl = "Oqtane.Client.Modules.Admin.ModuleSettings.Index, Oqtane.Client";
|
||||
public const string PageManagementModule = "Oqtane.Client.Modules.Admin.Pages, Oqtane.Client";
|
||||
public const string ModuleMessageControl = "Oqtane.Client.Modules.Controls.ModuleMessage, Oqtane.Client";
|
||||
public const string DefaultControl = "Index";
|
||||
|
||||
public const string AdminPane = "Admin";
|
||||
|
||||
public const string AllUsersRole = "All Users";
|
||||
public const string AdminRole = "Administrators";
|
||||
public const string HostRole = "Hosts";
|
||||
|
||||
public const int ReloadApplication = 3;
|
||||
public const int ReloadSite = 2;
|
||||
public const int ReloadPage = 1;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user