Another Abstract Factory & Strategy Pattern Explanation

Alright, I already know what you're thinking after reading the title, but that's why I prefaced it with "Another..." Long story short, I wrote this nice long e-mail to my friend/colleague here at work and I thought maybe it would be of use to one of the three people out there that haven't read 84 different explanations of the abstract factory pattern. Again, it was formally an e-mail so I ran through it and added some clarifications in brackets...hope I made _some_ sense :) A link to an explanation of the abstract factory pattern is here: http://69.10.233.10/KB/cs/Abstract_Factory_Pattern.aspx but IMO this stuff makes a lot more stuff in context. I tend to use this pattern a lot, but [to me] it seems to make a lot of sense when dealing with security/roles - it's an easy way to accommodate adding roles without having to go everywhere in your application and modifying code..but it can definitely be used elsewhere (I use it in JavaScript a lot too) Basically just create an interface with the method signatures you want to implement.

Public Interface ISecurityCheck
       Function canEditProfile(ByRef UserInfo As Object, ByVal ProfileID As String) As Boolean
       Function isAuthorizedPage(ByVal PageId As Integer, ByVal UserInfo As Object) As Boolean
  End Interface

Then, all you have to do is create a class for each role in your application. The class will implement the interface iSecurityCheck...This is what the implementation looks like for anonymous users in [my latest application]. Basically, anonymous users can read everything in [the application] but not write anything.

 

Public Class AnonymousSecurityCheck
       Inherits SecurityBase
       Implements ISecurityCheck
   
       Public Function canEditProfile(ByRef UserInfo As Object, ByVal ProfileID As String) As Boolean Implements ISecurityCheck.canEditProfile
           Return False
       End Function
   
       Public Function isAuthorizedPage(ByVal PageId As Integer, ByVal UserInfo As Object) As Boolean Implements ISecurityCheck.isAuthorizedPage
           Return isPageAllowed(PageId, UserInfo)
       End Function
   
  End Class

CanEditProfile takes a UserInfo object as a parameter which is basically my user object. There are a few propreties in UserInfo, but the most important ones are ProfileID and Role. CanEditProfile always takes a ProfileID parameter - this should probably be named better, but it is supposed to be the ProfileID of the page you're currently looking at. This allows me to cross-reference the UserInfo.ProfileID property with the ProfileID of the current page. In the case of the anonymous user, it returns false no matter what. isAuthorizedPage basically runs a stored proc to see if the user that is currently logged in can even load/view the page... The implementation of the rest of the roles looks like below, but there really isn't spectacular happening. Basically if you're a normal user, I return true for CanEditProfile assuming your UserInfo.ProfileID and the ProfileID of the page you're looking at is the same. isAuthorizedPage always runs the same stored proc (But the implementation could easily change) Admins can basically do whatever they want...so this always returns true for both functions:

Public Class AdministratorSecurityCheck
     Inherits SecurityBase
     Implements ISecurityCheck
 
     Public Function canEditProfile(ByRef UserInfo As Object, ByVal ProfileID As String) As Boolean Implements ISecurityCheck.canEditProfile
         Return True
     End Function
 
  
     Public Function isAuthorizedPage(ByVal PageId As Integer, ByVal UserInfo As Object) As Boolean Implements ISecurityCheck.isAuthorizedPage
         Return True
     End Function
 
End Class
 
 'CanEditProfile returns true only if the ProfileID = UserInfo.EmployeeID
 
blic Class UserSecurityCheck
     Inherits SecurityBase
     Implements ISecurityCheck
 
     Public Function canEditProfile(ByRef UserInfo As Object, ByVal ProfileID As String) As Boolean Implements ISecurityCheck.canEditProfile
         If TypeOf (UserInfo) Is AppMembershipUser Then
             If UserInfo.ProfileID.ToString = ProfileID Then Return True
 
         End If
         Return False
     End Function
 
  
     Public Function isAuthorizedPage(ByVal PageId As Integer, ByVal UserInfo As Object) As Boolean Implements ISecurityCheck.isAuthorizedPage
         Return isPageAllowed(PageId, UserInfo)
     End Function
 
 End Class

 

So that's all relatively straight forward. The best part of this is that you can add more roles, or change the business rules without a lot of work. So within a page, you use this like this: Dim isec As ISecurityCheck = AuthorizationFactory.GetAuthorization(UserInfo) CanEditProfile = isec.canEditProfile(Me.UserInfo, currentPageProfileId) So I get the true/false value telling me whether a user can edit a profile regardless of how many roles exist or whether I add or remove roles. Since you're running the CanEditProfile method yourself above which returns a value of type ISecurityCheck, this all works.

Public Class AuthorizationFactory
      Public Shared Function GetAuthorization(ByVal UserInfo As Object) As ISecurityCheck
  
          If TypeOf (UserInfo) Is AppMembershipUser Then
              UserInfo = CType(UserInfo, AppMembershipUser)
              With UserInfo
                  If Common.stringIsInArrayList(Constants.ROLE_ADMINISTRATOR, .rolename) Then Return New AdministratorSecurityCheck
                  If Common.stringIsInArrayList(Constants.ROLE_USER, .rolename) Then Return New UserSecurityCheck
             End With
         End If
 
         Return New AnonymousSecurityCheck
     End Function
 End Class

Hmm. This might be the longest e-mail I've written in a long time...Hope I did a decent job of explaining, though

Print | posted @ Wednesday, April 15, 2009 5:05 PM

Comments on this entry:

No comments posted yet.

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification:
 
 
Twitter