In Authorization Sample 201, I touched on some of the extensibility options for custom authorization. These include applying custom rules or setting target properties for custom bindings in xaml. I avoided the bigger picture, however, by neglecting to explain how it all works. In this section, I’ll tackle explaining the ins and outs of the authorization engine.
Attributes, Behaviors, and Rules
AuthorizationAttributes are the primary types for authorizing. They define the logic that determines whether something is allowed or not. All custom authorization implementations will start by defining a new attribute.
AuthorizationBehaviors are the primary types for applying authorization results to UI. They interpret the result and update the targeted object accordingly. For instance, the default behavior knows how to create Bindings for the attached property Authorization.TargetProperties.
AuthorizationRules are used to define the attributes and behaviors that will be applied to an object.
Invoking Authorization.Authorize() will run a target object through the following set of steps.
- Determine the AuthorizationRules that apply to the target
- Use those rules to determine all the AuthorizationAttributes that apply to the target
- Authorize the target by testing each attribute against WebContext.Current.User
There is one final step if the target is a DependencyObject. The rules are used to determine all the AuthorizationBehaviors that apply to the target, and then those behaviors are added to target.
As I describe above, AuthorizationRules are really what tie everything together. What I still need to explain is how rules are associated with an authorization target. Association occurs in two ways. First, targets start with a default set of rules based on their type. Second, specific rules can be added or removed from the collection of rules associated with a target. Both these responsibilities fall to the AuthorizationRuleManager. The manager tracks the rules for each target and allows you to access and update the them. Also, it allows you to set the default rules for a type (by passing in the type as the target). The following snippet adds a default rule and then gets the attributes for a specific target.
AuthorizationRuleManager.AddAuthorizationRule(typeof(MyType), myRule); AuthorizationRuleManager.GetAuthorizationRules(myType); // Contains myRule
If you inspect AuthorizationBehavior a little closer, you’ll notice it uses a type named AuthorizationSource. AuthorizationSource is a model that makes the AuthorizationResult (from step 3 above) available for binding. Additionally, anytime WebContext.Current.User is updated, it recalculates the result and raises the appropriate notifications.
Up until now, all examples have shown authorization being used solely with controls. That is definitely a primary use case, but it isn’t the only thing the authorization engine supports. In fact, you can authorize anything. The most common scenario where a non-control target is authorized is Uri authorization. The navigation part of the framework authorizes both the Uri and Page when navigating.
Hopefully this section gives you a better idea what the authorization library is really capable of. I have a number of small samples I hope to share in the coming weeks that use these extensibility points in all sorts of interesting scenarios including Site Map-based navigation and MVVM authorization.