He intentado muchos esquemas diferentes de permisos y solo he encontrado una forma de hacer que funcionen satisfactoriamente para el programador Y los clientes en casi todos los casos. Y esto es para hacerlos parcialmente impulsados por los datos.
Mi más reciente intento-funciona así:
- Cada usuario ha unido a él a los permisos de objetos. En mi caso, creado automáticamente cuando se solicita un usuario. (En mi caso, los permisos pueden ser diferentes para diferentes secciones. Por lo tanto, un usuario puede hacer X para Y pero no para Z.)
- Cada página, bloque de código o vista que debe ser permisiva se envuelve con if declaración que verifica el objeto de permiso. Si ese permiso también tiene que preocuparse por la sección, los ID de las secciones relevantes actuales se pasan como una matriz y devuelven una nueva matriz de bools para que coincida.
- La interfaz no expone este complicado problema a los usuarios directamente, sino que una interfaz superadmin permite crear nuevos tipos de usuarios. Estos tipos tienen conjuntos de permisos que se habilitarán para ese 'tipo' de usuario. Puede haber superposición en los permisos de diferentes tipos, por lo que tanto el administrador como el editor pueden "Editar Copia" o lo que sea.
- La interfaz de administración normal permite a los usuarios individuales establecerse como diferentes tipos de usuario para diferentes secciones. De modo que un usuario puede ser un administrador para la sección 2 y un editor para las secciones 2, 3, 4 y 5. También se pueden configurar globalmente, lo que sobrecarga una sección no utilizada (0).
Esto tiene muchos beneficios y un inconveniente. Primero, el inconveniente. Debido a que estas claves se hornean directamente en el código, solo una superadmina (también conocida como desarrollador) debe tener acceso a esa parte de la interfaz.De hecho, una interfaz puede no ser necesaria en absoluto, ya que la lista de permisos solo debería cambiar con el código. El verdadero problema aquí es que no sabrá que algo está mal con un título hasta que ejecute el código, ya que la sintaxis estará bien. Ahora, si esto fue codificado en algo como C#, este sería un problema muy serio. Pero casi todo en PHP no es seguro, por lo que es realmente justo para el curso. Estos valores también pueden cargarse desde un archivo de configuración, o incluso incluirse en la GUI desde la que crea los tipos de usuario, aunque eso parece incorrecto.
Lo que obtiene de esto es la capacidad de configurar nuevos tipos de permisos sobre la marcha. Obtiene la capacidad de cambiar el nombre de esos permisos con relativa facilidad. (Como el sistema solo usa el número, el título solo se usa para capturar el número, por lo que se puede cambiar fácilmente en unos pocos lugares). Y el código es muy simple de usar. Se vería algo como esto:
if($current_user->permissions->can("View Sales Records"))
{
//Code to view sales records
}
o ligeramente más complicado
$sections = array(1,2,3,4); //Probably really a list of all sections in the system
$section_permissions = $current_user->permissions->these($sections)->can("Edit Section");
foreach($sections as $s)
{
if($section_permissions[$s])
{
// Code for maybe displaying a list of sections to edit or something
}
}
El encadenamiento método es bastante simple también. ->these()
establece una matriz interna a esos valores y luego devuelve una referencia al objeto en sí. ->can()
luego actúa en esa lista, si existe, y luego la desactiva. En mi propia versión también tengo ->any()
que siempre devuelve una lista completa de secciones, por lo que puedo verificar ->any()->can()
.
Finalmente, el objeto de permiso también contiene una lista de qué tipos es un usuario. Lo que hace que sea realmente fácil mostrar una lista de usuarios y qué permisos tienen activa. En mi caso, solo usamos ->types()
para acceder a esa lista y una matriz de ids => names
.
Los títulos de permisos no presentes simplemente se ignoran. También se combinan en minúsculas y con espacios y caracteres especiales eliminados para ayudar a disminuir los problemas de tipeo. He considerado incluso hacer un control de distancia levenshtein y escoger la pareja más cercana. Pero al final, es mejor no confiar en algo así. (tal vez registrar el error, pero con gracia seleccione la coincidencia más cercana.)
Fuera del código y en la interfaz, los usuarios solo necesitan relacionarse entre sí en un sistema Fulano es un Administrador, Editor, Editor Escritor y CEO, etcétera. También sería trivial crear diferentes conjuntos de tipos de usuarios para diferentes organizaciones.
Todas las partes de esto se pueden almacenar en caché, la configuración de un usuario básico para las personas que no han iniciado sesión es muy fácil, y todavía tengo que encontrar un problema basado en permisos que no es obvio para resolver usando esta estructura.
Ojalá pudiera compartir el código real con usted. Simplemente no soy dueño de mí mismo y, por lo tanto, no puedo publicarlo.
Estoy ansioso por encontrar una respuesta a esta también. Estamos usando un modelo de fiesta y estamos considerando hacer que el "cliente" tenga un rol en la aplicación con sus propias afirmaciones (en Zend ACL), pero parece torpe. – boatingcow