I have had this question for quiet long and thought of seeking wisdom of the crowd here.
In my application there are 10 user roles allowed. Its an ASP.NET MVC2 application. Each controller method can be accessed by a specific user role only.
For implementing this I created a UserRoleType Enum.
public enum UserRoleType
{
SystemAdministrator = 1,
SeniorLevelExecutive = 2,
SeniorManager = 3,
JuniorManager = 4,
SeniorAdmin = 5,
JuniorAdmin1 = 6,
JuniorAdmin2 = 7,
SeniorAppraiser = 8,
JuniorAppraiser = 9,
SeniorResearch = 10
}
These values match with whats in database (UserRole table with 10 rows).
Also the UserRoleId of a user is stored in [User] table. As soon as a user logs in we开发者_运维百科 get the roleId of the user from the database and match this to the above enum. For instance if the roleId of the user was 4, it means he/she is a Junior Manager.
This application is not in production now. The only drawback I see is when we go live if for some reason the value in User Role Type table did not match the Enum we will be in big trouble. What are the alternatives? Or should I just concentrate on making sure that we have the matching values in database. Any help will be highly appreciated.
Thanks a lot!
My opinion is, that if you can't trust your own configuration in the DB and Config files, you're up the creek anyways. Just make sure your DB records have that value as a specific column value, not the auto generated row ID.
Don't log the user in if the value for RoleID is not in the range of the Enum.
I would send an email to the admin to fix the issue.
A simple method would be to add a Name field to the UserRole table, and at your application startup, iterate over your enumeration, look up that UserRole by ID, and make sure the name matches UserRoleType.ToString(). You should be able to implement this without any major code changes.
private void VerifyUserRoles()
{
foreach (UserRoleType role in Enum.GetValues(typeof(UserRoleType)))
{
string dbName = /* SELECT Name FROM UserRole WHERE UserRoleId = (int)role */;
if(role.ToString() != dbName) throw new Exception();
}
}
A more complex method would be to not have an enum at all. If you want to have the list of roles be completely database driven, then make UserRoleType a class with a private constructor, and have it do a database read to create the list of objects. (I imagine there's a name for this pattern, not sure what it is, though.) Obviously, this would be a more significant change to your existing code.
public class UserRole
{
static List<UserRole> roles = new List<UserRole>();
static UserRole()
{
foreach (/* SELECT * FROM UserRole */)
{
roles.Add(new UserRole(...));
}
}
private UserRole(...){...}
// Permissions that the role consists of.
private bool CanEditEverything { get; private set; }
// Use this whenever you need to display a list of UserRoles.
public static ReadOnlyCollection<UserRole> AllUserRoles { get { return roles.AsReadOnly(); } }
// If you still need to explicitly refer to a role by name, rather than
// its properties, do these and set them in the static constructor.
public static UserRole SystemAdministrator { get; private set; }
}
I do this but add the appropriate constraints to the DB, with the constraint description directing the reader to the enum.
I am not sure you should be using a static data structure like an enum to model the elements from a dynamic one like a table. Would it not be better to have a UserRole
entity class and a UserRoleCollection
collection class? That way the set of user roles can be a bit more dynamic. Of course, anytime your code uses these data structures you would have to make sure you build in a failsafe mechanism that causes access to a particular resource to always be denied if an unknown user role is encountered. Naturally the code would generate a descriptive message if an unknown role somehow got entered into the database.
精彩评论