Herramientas web2pyTM

Desde la versión 1.56 web2py incluye herramientas para autenticación, autorización, ABM (CRUD), servicios web, y más. Son implementadas para no requerir JOINs y por lo tanto funcionan también en Google App Engine.

Autenticación

La herramienta básica de autenticación es la clase Auth. Provee métodos que pueden ser usados como acciones de controlador para registrar usuarios (opcionalmente con soporte Recaptcha), registrar su acceso y egreso (iniciar sesión), permitir verificación por correo electrónico, cambio, restablecimiento y recuperación de contraseña, edición del perfil de usuario.

Estas funcionalidades pueden ser usadas como las bases para autorización.

Las llamadas a Auth pueden ser extendidas, personalizadas, y reemplazadas por otros mecanismos de autenticación que expongan una interfaz similar.

Para usar autenticación, escribir algo parecido a esto en el archivo del modelo:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
from gluon.tools import Mail, Auth, Recaptcha

mail = Mail()
## especificar el servidor SMTP de correo saliente
mail.settings.server = 'smtp.sudominio.com:25'
## especificar su dirección de correo
mail.settings.sender = 'ud@sudominio.com'
## opcional: especificar el nombre de usuario y contraseña para SMTP
mail.settings.login = 'usuario@clave'

## instanciar la clase Auth (o su propia clase derivada)
auth = Auth(globals(), db)
## preguntar si crear todas las tablas necesarias
auth.define_tables()
## opcional: requiere verificación por correo electrónico para registración
# auth.settings.mailer = mail
## opcional: si requiere verificacioón captcha para registración
# auth.settings.captcha = Recaptcha(request,public_key='RECAPTCHA_PUBLIC_KEY',private_key='RECAPTCHA_PRIVATE_KEY')

En su controlador (por ejemplo en default.py) exponer los objetos auth (por ejemplo vía una acción user):

1.
2.
def user():
return dict(form = auth())

La acción de arriba expondrá las siguientes URLs

La página groups muestra una lista de los roles y la descripción para los grupos en el que el usuario que inició sesión es miembro (ver autorización).

Puede verificar si un usuario inició sesión vía auth.is_logged_in(). Si un usuario inicio sesión su información de registro puede ser encontrada en auth.user. Por defecto un usuario es almacenado en la tabla llamada "auth_user" y tiene las siguientes columnas: first_name, last_name, email, password. La contraseña es almacenada encriptada (md5 hashed o superior). Puede cambiar el nombre de la tabla, definir su propia tabla con más campos, requerir validadores adicionales.

Todos los eventos de autenticación son registrados en una tabla llamada "auth_event".

Autenticación Personalizada

Puede personalizar el objeto auth cambiando sus ajustes y mensajes:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
auth.messages.access_denied = 'Privilegios insuficientes'
auth.messages.logged_in = 'Sesión iniciada'
auth.messages.email_sent = 'Correo electrónico enviado'
auth.messages.unable_to_send_email = 'Incapaz de envíar correo electrónico'
auth.messages.email_verified = 'Correo electrónico verificado'
auth.messages.logged_out = 'Sesión finalizada'
auth.messages.registration_successful = 'Registración satisfactoria'
auth.messages.invalid_email = 'Correo electrónico inválido'
auth.messages.invalid_login = 'Inicio de sesión inválida'
auth.messages.invalid_user = 'Usuario inválido'
auth.messages.mismatched_password = "Los campos de contraseña no coinciden"
auth.messages.verify_email =
'Presione en el enlace http://...verify_email/%(key)s para verificar su correo electrónico'
auth.messages.verify_email_subject = 'Verificar contraseña'
auth.messages.username_sent = 'Su nombre de usuario le fue enviado por correo'
auth.messages.new_password_sent = 'Una nueva contraseña le fue enviada por correo'
auth.messages.password_changed = 'Contraseña cambiada'
auth.messages.retrieve_username = 'Su nombre de usuario es: %(username)s'
auth.messages.retrieve_username_subject = 'Recuperar nombre de usuario'
auth.messages.retrieve_password = 'Su contraseña es: %(password)s'
auth.messages.retrieve_password_subject = 'Recuperar contraseña'
auth.messages.profile_updated = 'Perfil actualizado'
auth.messages.new_password = 'Nueva contraseña'
auth.messages.old_password = 'Vieja contraseña'

Las cadenas pueden ser traducidas ende la maera usual aún si no hay un operador T

Las vistas pueden ser manejadas de la forma habitual de web2pyViews are handled the usual web2py way.

También es posible usar tablas personalizadas. Por ejemplo una tabla de usuario personalizada:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
# instanciar auth
auth=Auth(globals(),db)

# definir las tablas personalizadas (table_user_name es 'auth_user')
auth.settings.table_user = db.define_table(
auth.settings.table_user_name,
Field('first_name', length=512,default=''),
Field('last_name', length=512,default=''),
Field('email', length=512,default='',
requires = [IS_EMAIL(),
IS_NOT_IN_DB(db,'%s.email'%auth.settings.table_user_name)])
Field('password', 'password', readable=False,
label='Password', requires=CRYPT()),
Field('registration_key', length=512,
writable=False, readable=False,default=''))

# definir cualquier otra tabla requerida
auth.define_tables()

Uno puede agregar cualquier otro campo que se necesita siempre y cuando los campos en el ejemplo esten allí.

Autorización

Una vez que tenga identificado al usuario por el user.id, puede crear un grupo (por ejemplo "Administrador")

group_id = auth.add_group(role = "Administrador", description = "ejemplo de grupo")

y hacerlo miembro al usuario:

auth.add_membership(group_id,user_id)

y asignarle permisos a todos los miembros del grupo:

auth.add_permission(group_id,'create','tablename',record_id)

Luego puede hacer cumplir los permisos usando los siguientes decoradores:

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
auth.settings.on_failed_authorization=URL(r=request,f='error')

@auth.requires_login()
def some_function1():
return dict()

@auth.requires_membership('Administrador')
def some_function2():
return dict()

@auth.requires_permission('create','tablename',1)
def some_function3():
return dict()

def error():
return dict(message = T("no autorizado"))

Los roles de grupo son convencionales. Los nombres de permisos son también convencionales. Si un grupo tiene ciertos permisos en el record_id==0 (predeterminado), significa que el usuario tiene permisos sobre cualquier registro.

Algunos nombres de permisos ("tables", "select", "create", "update", "delete", "read") tienen un significado especial ya que pueden ser automáticamente comprobados por la herramienta ABM descripta abajo.

Altas/Bajas y Modificaciones (Create/Read/Update/Delete y más)

Para usar CRUD (ABM), en su modelo inserte el siguiente código:

1.
2.
from gluon.tools import Crud
crud = Crud(globals(),db)

y en uun controlador (por ejemplo en default.py) expongalo vía una acción (por ejemplo data):

1.
2.
3.
4.
5.
def data():
return dict(form = crud())

def download():
return response.download(request, db)

Esto expondrá las siguientes URLs:

"tables" lista las tablas de la base de datos actual.

"download" solo permite bajar archivos subidos (tanto si estan en la carpeta de subidas o en la base de datos).

Para hacer cuplir la autorización en estas URLs CRUD simplemente establezca

1.
crud.settings.auth=auth

y el usuario con sesión iniciada solo será capaz de "create" (crear) un registro en la tabla "tablename" si el usuario es miembro del grupo que tiene permisos "create" en la tabla "tablename". El mismo mecanismo funciona para URLs "tables", "select", "read", "update", y "delete".

Servicios

Web2py provee una interfaz para exponer cualquier función como un servicio (CSV, XML, JSON, XMLRPC, JSONRPC, AMF)

Esto se logra en tres pasos:

La función puede ahora ser llamada remotamente usando la sintaxis

1.
http://..../app/default/call/[method]/[function]/[arguments]
or
1.
http://..../app/default/call/[method]/[function]?[arguments]
for example
1.
2.
http://..../app/default/call/run/myfunction/2/3
http://..../app/default/call/json/myfunction/2/3
or
1.
2.
http://..../app/default/call/run/myfunction?a=2&b=3
http://..../app/default/call/json/myfunction?a=2&b=3

Salvedades: csv solo funciona si la función regresa una lista de listas. amfrpc solo funciona si PyAMF está instalado. En el caso de xmlrpc, jsonrpc y amfrpc, los argumentos arguments (/myfunction/2/3) no pueden ser pasados en la URI, deben ser pasados de acurdo al protocolo respectivo. Por ejemplpo para xmlrpc desde otro programa python:

1.
2.
3.
>>> from xmlrpclib import ServerProxy
>>> server = ServerProxy('http://..../app/default/call/xmlrpc')
>>>
print server.myfunction(2,3)

Traer una URL

El módulo Python urllib no funciona bien en Google App Engine. Por esta razón hemos creado una función portable para traer url que funciona en todas partes, incluyendo GAE:

1.
2.
from gluon.tools import fetch
html = fetch("http://www.web2py.com")

Codificación Geográfica (geocoding)

Otra forma muy com´´un de aplicaciones web moderas es vonvertir una dirección a una longitud y latitud. Tambien proveemos una función portable para hacerlo que usa la API de Google Geocoding:

1.
2.
from gluon.tools import geocode
(latitude, longitude) = geocode("Balcarce 50, Buenos Aires, Argentina")

Devuelve 0,0 si hay falla.