Tuesday, April 1, 2014

Adding security to a menu

For WPF 4.0

Most applications need to be able to hide/show or disable/enable menu items based on the current user's security. Our applications all use a home-grown security provider that, after an eight-table join, returns a list of security codes that control the user's access to features. The security codes have simple names like "CreatePO" and "Requisition". I need to be able to only show menu items when the user has the correct security code.

At first I thought the solution would be like the asp.net security provider which allows the developer to write an event handler that is called prior to rendering each menu item. The event handler decides whether the menu item should be displayed or hidden. However the WPF menu class does not seem to have such an event defined.

After a little thought and some coffee, I realized I could bind each menu item's visibility to the user's security codes using a converter and pass the desired security code(s) through the converter parameter. This turns out to be a pretty good solution.

The user's security codes and their descriptions are held as a dictionary of string, string in an application property. Here is a converter that takes a comma delimited list of security codes. If the user has any of them, the menu item will be visible. Otherwise it will be collapsed.

Public Class SecurityConverter
    Implements IValueConverter

    Public Function Convert(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
        Dim Codes As Dictionary(Of String, String) = Application.Current.Properties("User_SecurityCodes")
        For Each p As String In parameter.ToString.Split({","c}, StringSplitOptions.RemoveEmptyEntries)
            If Codes.ContainsKey(p) Then
                Return Visibility.Visible
            End If
        Next
        Return Visibility.Collapsed
    End Function

    Public Function ConvertBack(value As Object, targetType As System.Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
        Throw New NotImplementedException("SecurityConverter")
    End Function
End Class

Then we create a static resource so we can reference the converter. In the window's opening tag we add a reference to our namespace

     xmlns:local="clr-namespace:<insert namespace here>"

and add a static resource to the Resources so we can reference our converter.

    <local:SecurityConverter x:Key="SecurityConverter"/>

Now we can bind the Visibility of selected menu items to the user's security codes like this...

    Visibility="{Binding Converter={StaticResource SecurityConverter}, ConverterParameter='Requisition'}"

No comments:

Post a Comment