Estoy mirando el diseño de mi interfaz y estoy luchando para decidir cuál es la forma más "correcta" de implementar el control de acceso basado en roles, dado a user
y a los subject
que user
les gustaría acceder.
Por lo que puedo ver, tengo tres opciones principales (una cuarta es una bastardicación de las tres primeras y una quinta es una modificación de la cuarta):
- Consulta
subject
con una lista de permisos queuser
tiene:subject.allowAccess(user.getPermissionSet)
- Consulte
user
con una lista de permisos quesubject
requiere:user.hasPermissionTo(subject.getRequiredPermissions())
- Consultar a un tercero para ubicar las intersecciones de permisos:
accessController.doPermissionSetsIntersect(subject.permissionSet, user.getPermissionSet())
- Consulte el
subject
/user
, mientras delega la "decisión" a una clase de terceros - Intente
user
accedersubject
y arroje un error si no se permite el acceso
Me estoy inclinando hacia la opción cuatro: que subject
contenga un accessController
campo, donde las llamadas para subject.userMayAccess(User user)
delegar la operación a la:
class Subject {
public function display(user) {
if(!accessController.doPermissionSetsIntersect(this.permissionSet, user.getPermissionSet())) {
display403(); //Or other.. eg, throw an error..
}
}
}
.. pero esto plantea más preguntas:
- ¿Debería
accessController
ser un campo frente a una clase estática? - ¿Debería
subject
saber qué permisos se requieren para poder verlo? - ¿Dónde entra en juego aquí el principio de menor conocimiento, con respecto al llamado
subject.display()
? ¿Deben las personas que llamansubject.display()
saber que el control de acceso está vigente? (dondesubject.display()
es un "método de plantilla" final) - ¿ha
subject.display()
administrado el control de acceso, lanzando una excepción donde el usuario no tiene el permiso requerido?
¿Qué se consideraría "mejor práctica" en esta situación? ¿Dónde debería ocurrir la responsabilidad de realizar las verificaciones?
Como esto es algo tanto un ejercicio académico que luego progresará en la implementación, se agradecerán las referencias a los patrones de diseño.
Creo que su opción 3 es la más cercana, pero en lugar de interrogar sobre
user
ysubject
sobre sus conjuntos de permisos, debe pasar eluser
ysubject
al controlador de acceso.El controlador de acceso debe ser responsable tanto de obtener los conjuntos de permisos como de verificar si el acceso es suficiente. De esa manera, aísla tanto la lógica de almacenamiento como la lógica de verificación en su controlador de acceso, separadas del usuario y del sujeto.
El otro elemento que posiblemente falta en su ejemplo es qué operación se está realizando. Algunos usuarios pueden tener el derecho de leer algunos datos pero no a actualizar, eliminar, ejecutar, etc. Por lo que podría tener un
checkAccess
método en el controlador de acceso con tres parámetros:user
,subject
,operation
. También es posible que desee proporcionar alguna información adicionalcheckAccess
para devolver información sobre por qué no se otorgó el acceso.Por ejemplo, delegar todo esto al controlador de acceso más adelante le permite reemplazar la forma en que se representan sus permisos. Puede comenzar con el control de acceso basado en roles y pasar a los basados en notificaciones más adelante. Puede almacenar permisos en una estructura simple para comenzar y luego agregar grupos / roles jerárquicos y operaciones permitidas sobre diferentes tipos de temas. No poner sus conjuntos de permisos en la interfaz ayuda a habilitar esto.
Si usa AOP o algún código repetitivo para conectar esto, en mi opinión, es menos importante.
fuente