Till now I've used very simple User-Role version and controlled permissions per Visibility / IsEnabled / Command.CanExecute with converters:
<TabItem Visibility="{Binding UserRole, Converter={StaticResource PackerVisible}}" >...
My converter looks like:
<conv:UserVisibilityConverter x:Key="PackerVisible" Allow="Packer,Lagerleiter,Entwickler" />
It's relative easy if you have not much roles, but even so you have no good overview: who will get access to this or other UI elements.
One more bad thing is that UserRoles (stored in DB) used here as strings - Allow="Role1, Role2, Role3".
And in my new project I have more roles/permissions, what makes this solution more ugly.
I've searched and found nothing how to implement it much better. A bit better is maybe to use enum for role names in code, but how to synchronise enum with database?
Other solutions i've found (solution1, solution2) are better, because they don't need converters, but permissions are set again as strings in XAML:
// AuthToVisibility
<Image ... Visibility="{op:AuthToVisibility "CanView"}" />
// AutoToEnabled
<MenuItem IsEnabled="{op:AuthToEnabled "CanClose"}">...</MenuItem>
What is the best way to handle permissions stored in the database towards UI? Is there any pattern?
As long as nobody answers, I will try. I have a better (not ideal) solution.
First implementation, below I will write some words about it.
Permission Class:
public class Permission
{
public bool IsAllowed { get; set; }
internal List<string> AccessControllList { get; private set; }
internal Permission(params string[] allowedRoles)
{
IsAllowed = false;
AccessControllList = new List<string>();
foreach (var role in allowedRoles)
{
AccessControllList.Add(role);
}
}
}
IsAllowedAccessControlList which are allowed to run/see some function/blockPermissionController:
public class PermissionController : INotifyPropertyChanged
{
#region Singleton
...
//constructor
private PermissionController()
{
Initialize();
UserModel.Instance.LoginChanged += new LoginChangedEventHandler(UpdatePermissions);
}
#endregion
//role names from database as string const
private const string PACKER = "Packer";
private const string CHIEF = "Lagerleiter";
private const string QSWORKER = "QSMitarbeiter";
private const string DEVELOPER = "Entwickler";
PropertyInfo[] _localProperties;
//Permissions defined as properties
public Permission WEstart { get; private set; }
public Permission WEreset { get; private set; }
public Permission WEclose { get; private set; }
public Permission Manage { get; private set; }
public Permission TestPhase { get; private set; }
private void Initialize()
{
_localProperties = typeof(PermissionController).GetProperties();
WEwork = new Permission(PACKER, CHIEF);
WEreset = new Permission(CHIEF);
WEclose = new Permission(PACKER, CHIEF);
Manage = new Permission(CHIEF);
TestPhase = new Permission(DEVELOPER);
}
private void UpdatePermissions(object sender, EventArgs e)
{
var currentUser = (UserModel)sender;
//if user is logged out -> return
if (!currentUser.IsLoggedIn)
return;
var permissionType = typeof(Permission);
foreach (PropertyInfo property in _localProperties)
{
if (property.PropertyType != permissionType)
continue;
var permission = (Permission)property.GetValue(this, null);
permission.IsAllowed = false;
if (permission.AccessControllList.Contains(currentUser.UserRole))
{
permission.IsAllowed = true;
}
OnPropertyChanged(property.Name);
}
}
#region INotifyPropertyChangedImplementation
...
protected virtual void OnPropertyChanged(string propertyName)
{
...
}
...
#endregion
}
INotifyPropertyChanged (to use its properties directly in XAML)const strings for user roles defined in database. It's only one place in code where user roles are used as string values. If you need to update the role list - you should change only const list and initialization method (Permissions initialization). IsAllowed properties of each Permission.Different converters (IValueConverter) to convert Permission object (set in XAML) to Visibility/IsEnabled Property (can post code if you need)
XAML:
<Image Visibility="{Binding Permissions.TestPhase, Converter={StaticResource PermissionToVisibility}}" ... />
<TextBox IsEnabled="{Binding Permissions.WEwork, Converter={StaticResource PermissionToBoolean}}" ... />
<Button Command="..." CommandParameter="{Binding Permissions.Manage}" ... />
Now I can manage User roles in GUI freely, role permissions are defined only in code. But it wasn't my requirement to manage role permissions.
Good enough is that if I need to update/change role permissions I will do it in only one place in code.
If you have questions or recomendations - I'm open for a dialog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With