In a project I have 3 Actors (user,expert,admin) and 5 main Use cases(CRUD: create,read,update,delete and Sync). But access of users to each use case differs from other Actors.For example user can create one entity,but expert and admin can create arbitrary number,and so on other use cases:
Also,actors use same UI.So I have to decide for enabling or disabling actions respect to the current actor at run time.It seems easy to do that,but I like to have a good design.Specially, number of use cases,actors and their access right level may change later.So I have to respect to OCP principle.But how I can have a good design to manage use cases and actors's access right level?
Java comes with very simple but powerful security idea. Principal (user) holds some permissions and object (entity) can require some permissions to be processesd somehow.
import java.security.Permission;
import java.security.Permissions;
import java.security.SecurityPermission;
public class PermissionFactory {
public static Permission createOneEntity() {
return new SecurityPermission("entity.create.one");
}
public static Permission createManyEntities() {
return new SecurityPermission("entity.create.many");
}
public static Permission deleteEntity(Entity e) {
return new SecurityPermission("entity.delete." + entyty.getOwnerId());
}
public static Permission deleteMyEntity(User owner) {
return new SecurityPermission("entity.delete." + user.getId());
}
public static Permission deleteAnyEntity() {
return new SecurityPermission("entity.delete.*"); // * is a placeholder for 'any'
}
}
public class User {
private final Permissions permissions = new Permissions();
public void addPermission(Permission p) {
if(p != null) {
this.permissions.add(p);
}
}
public boolean hasPermission(Permission p){
return permissions.implies(p);
}
}
When you create users you can store their permissions along with them.
User admin = new User();
admin.addPermission(PermissionFactory.deleteAnyEntity());
User regular = new User();
regular.addPermission(PermissionFactory.deletyMyEntitiy(tregular);
And finally when you need to perform some protected action you can ask principal if he has enough permissions to do that.
Entity object = ...;
if(regular.hasPermission(PermissionFactory.deleteEntity(object)) {
delete object
}
You can open you interface if you add notions of 'action' and 'entity type' for example, and then instead of static methods in PermissionFactory provide some permission builder interface. But anyhow security model and OCP are orthogonal to each other.