I have an app that have multiple users. In my app an user can
– create contacts (people)
– edit contacts
– view contacts
– create an entry to agenda
– view entry from agenda
Also I need that User A is allowed to view User’s B contacts but is not allowed to edit that contact.
User B can view and edit User’s A entries in Agenda. The app will have about
10-15 permission for each module (Agenda, Contacts, Documents, EmailMarketing) and the number of modules can reach to about 20
Let’s say “User A” is a sales person, and “User B” is the sales manager.
For sure, each Business Object (contact, agenda entry,etc) will have a owner id.
What is the best approach/design patter/good practice to use to handle this situation?
1
- Use a database table that encodes the user permissions for various operations.
- Write an access manager that sits in front of the DB.
- For each potentially restricted operation, first check as a precondition that the access is valid. This is too complex for most type systems so it will have to be done as code. If the access in invalid, throw an exception or abort otherwise.
Example:
abstract class BusinessObject {
User owner;
AccessManager access;
...
}
class Contact extends BusinessObject {
void edit(User byUser) {
access.validate(this, byUser, Operation.EDIT);
... // normal code
}
}
class AccessManager {
...
boolean check(BusinessObject subject, User user, Operation op) {
// pseudocode
results = db.execute("SELECT 1 FROM permissions WHERE subject=? AND user=? and operation=?", subject.id(), user.id(), op.id());
return results.length > 0;
}
void validate(BusinessObject subject, User user, Operation op) {
if (check(subject, user, op))
return;
throw AccessViolation(user + " does not have permission to " + op + " on " + subject);
}
}
class Context {
void execute() {
try {
someContact.edit(someUser);
}
catch (AccessViolation e) {
logger.log(e);
displayPrettyError("Sorry, you don't have permission to edit that contact. " +
"You can ask " + someContact.owner().name() + " for permission.");
}
}
}