As I am somewhat new to the OO game, I am still struggling to realign my data-centric way of thinking to one that is more responsibility focused. With that acknowledgement...
I am facing a bit of a problem designing objects to handle User management in my application. Specifically, I am trying to satisfy the following general use cases:
1. All users can Get/View non-sensitive user information.
2. An Administrator can Add, Edit and Delete any user information.
3. A user can Edit certain portions of his or her own user information (i.e., password, last name, etc.)
My first approach was to create the following objects:
- UserList (read-only list containing UserInfo objects)
- UserInfo (read-only, non-sensitive user information that can be viewed by all users)
- User (editable root object containing all user information and related methods)
The User object contains all of the user's information, including account related stuff such as FailedLoginAttempts, IsLockedOut, IsActive, etc. In addition to the standard CRUD methods, the object also contains methods for managing the User's account (e.g., SetPassword, LockUser , UnlockUser, etc.).
The problems I am facing are centered around authorization. My User object is a nightmare! I have to implement three levels of authorization to properly control who can do what within the object:
1. Type Level (CanAddObject, CanGetObject, CanEditObject, CanDeleteObject) - To provide high level access to the object.
2. Instance Level (IsReadable, IsEditable, IsDeleteable) - To allow a user to edit his or her own object.
3. Property Level (CanReadProperty, CanWriteProperty) - To control access to each property.
Further, I am realizing that I also need to implement Method Level authorization for methods such as LockUser and UnlockUser. From the UI perspective, this object is cumbersome and is not very databinding friendly (does the UI call static, instance, property or method authorization, and under what circumstances?)
Ultimately I have come to the conclusion that I have missed the OO mark on this one. Can someone provide me with some guidance?
I am considering the following objects:
UserList and UserInfo - as described above
User - containing all user information and related methods, but restricted to Administrator (maybe this should be split into User and UserAccount?). This would implement Type Level authorization.
UserOwned - containing information and methods that can be edited/executed only by the owning user (e.g., ChangePassword). This would implement Instance Level authorization.
How are others doing this? Any help would be appreciated.
Your UserEdit object and UserInfo object should be quite different from your princpal object.
I would expect that you'd (at least) have the following:
To get your editing authorization correct you'd do:
Of course your UserPrincipal/UserIdentity would be a read-only representation of the currently logged in user's identity/roles. If you want live updates, you could have UserEdit notify UserIdentity (using a Friend/internal method) that it is invalid so it could reload itself.
Single responsibility design says that an object should have
exactly one responsibility.
The principal/identity objects have a very clear responsibility:
provide identity and role information about the current user.
The responsibility to edit that data is entirely
different, and so it must be a different object. In other words, the
principal/identity objects shouldn’t be responsible for editing the data
they contain in addition to providing identity/role information for the
application.
Rocky
You might want to also look into the protection proxy design pattern.
Copyright (c) Marimer LLC