Setting WPF UI Permissions in Code Behind

2019-02-20 04:11发布

问题:

I am looking to see if I can do the following in WPF:

A user opens the WPF application and using the users AD name I will check the users role(s) in a custom DB. This will be something similar to asp.net membership db.

Depending on the user role the WPF will show certain controls.

So for example, if I was an Admin then I would have access to everything but if I was read-only user then I would have limited access to the application.

I know I can set the visibility using the following example:

public class RoleToVisibilityConverter : MarkupExtension,IValueConverter
{
    public RoleToVisibilityConverter()
    {

    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo                                 culture)
    {
        var principal = value as GenericPrincipal;
        bool IsValidUser = false;
        if (principal != null)
        {
            foreach (String role in parameter.ToString().Split(';'))
            {
                if (principal.IsInRole(role))
                {
                    IsValidUser = true;
                    break;
                }  
            }
            return IsValidUser ? Visibility.Visible : Visibility.Collapsed;
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}

And in the XAML I add the following binding for Visibility:

Visibility="{Binding Source={x:Static systhread:Thread.CurrentPrincipal}, ConverterParameter=admin;editor;readonly, Converter={rv:RoleToVisibilityConverter}}

But what I want to do is to not have to add this in xaml.

I would like to be able to get the users role and all of it's permissions and depending on the window load the UI permissions.

Reason is that I would like to be able to change what a read-only role can see/do without having to change the xaml.

Does anyone know if this is possible and if so is it best practice.

Thanks in advance.

Noel

回答1:

If you're using MVVM, then your view model should have properties such as public bool IsXXXAllowed { get; private set; }. When the view model is instantiated you should query whether the user has the minimum permissions required to use XXX feature and set the value of the property accordingly. The permission check should ideally be agnostic of roles since roles can be user created for nesting etc. You can directly query the permissions on a table using fn_my_permissions.

Then in the view simply bind the IsEnabled property (or Visibility property using BooleanToVisibilityConverter) of the relevant control (or a Grid enclosing the controls if there is more than one control) to the IsXXXAllowed property.



回答2:

I believe "Not done in Xaml" is virtually impossible unless you are willing to create different views for each different permission and during Navigation target the appropriate user permission page.

Otherwise...the best thing you can do is create a style. This style will target the base control and within the definition create a data trigger(s) which will turn on/off visiblity or IsEnabled or both. That way the style can live in one central location for all xaml pages and each control that needs the permissions flagging has it by simply adhering to that style.

Another benefit of that is you can bind different scenarios depending on needs. For example the below style has differing booleans set on the data context. One might be able to view but not edit, so the IsEnabled is set to false for that user while an admin would be allowed to do both, while a non viewable flagged user would not even see the control.

<Style x:Key="PermissionStyle" TargetType="{x:Type Control}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=ViewOnly}" Value="True">
            <Setter Property="Visibility" Value="Visible" />
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=IsAdmin}" Value="True">
            <Setter Property="IsEnabled" Value="True" />
            <Setter Property="Visibility" Value="Visible" />
        </DataTrigger>
        <DataTrigger Binding="{Binding Path=NotVisible}" Value="True">
            <Setter Property="IsEnabled" Value="False" />
            <Setter Property="Visibility" Value="Hidden" />
        </DataTrigger>            
    </Style.Triggers>
</Style>