I have class that represents user authorization (scala code):
case class Authorization(
userId: UUID,
permissions: Seq[String],
userRoles: Seq[String],
companyId: UUID
) {
private val policy = new Policy(permissions)
def isAllowed(path: String, action: String): Boolean = policy.isAllowed(path, action)
def isSuperuser: Boolean = userRoles.contains(SuperUser)
}
This class is used in many places in application to check whether user has specific permission for specific entities, e.g.:
authorization.isAllowed(s"some/entity/path/$id", "read")
To improve usability and avoid direct string manipulation I wrapped such methods in more specific ones:
def canViewCompany(companyId:UUID)=authorization.isAllowed(s"company/$companyId","read")
def canViewUser(userId:UUID)=authorization.isAllowed(s"user/$userId","read")
def canEditTask(id:UUID)=authorization.isAllowed(....)
....
and so on, up to 20 methods.
Should Authorization contain such methods like canViewCompany() ?
Is it responsibility of this class to know about each specific entities check?
UPDATED: So eventually questions are:
- Is it a good idea to create wrappers like
canViewCompany(companyId:UUID)in order to improve usability of the class? - If so, should these methods beplaced in
Authorizationitself or to be extracted to some service like:PermissionService.canViewCompany(id,authorization)=authorization.isAllowed()?
My approach would be to load a UserPrincipal (paraphrasing .net) with all the permissions and have a method that would check if certain permission is in the
Seq[Permissions].Permissioncould be an object with thepathandaction. Using this approach, you don't need to create an army of methods. Just one method that is going to validate the path and the action. Also, it allows you to pass this object across your application without worrying about checking the database in each operation.In a nutshell, you should have a service that takes care of the Authentication/Authorization. This service creates a UserPrincipal with all the data you need to check for access.
Does it make sense?