fastapi-djauth 1.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fastapi-djauth might be problematic. Click here for more details.
- fastapi_djauth-1.4.0/.gitignore +10 -0
- fastapi_djauth-1.4.0/CHANGELOG.md +73 -0
- fastapi_djauth-1.4.0/CONTRIBUTING.md +62 -0
- fastapi_djauth-1.4.0/LICENSE +20 -0
- fastapi_djauth-1.4.0/PKG-INFO +133 -0
- fastapi_djauth-1.4.0/README.md +85 -0
- fastapi_djauth-1.4.0/SECURITY.md +23 -0
- fastapi_djauth-1.4.0/djauth/__init__.py +82 -0
- fastapi_djauth-1.4.0/djauth/__main__.py +98 -0
- fastapi_djauth-1.4.0/djauth/api.py +890 -0
- fastapi_djauth-1.4.0/djauth/backends.py +130 -0
- fastapi_djauth-1.4.0/djauth/core.py +1280 -0
- fastapi_djauth-1.4.0/djauth/database.py +148 -0
- fastapi_djauth-1.4.0/djauth/decorators.py +119 -0
- fastapi_djauth-1.4.0/djauth/errors.py +107 -0
- fastapi_djauth-1.4.0/djauth/fields.py +157 -0
- fastapi_djauth-1.4.0/djauth/hashers.py +54 -0
- fastapi_djauth-1.4.0/djauth/models.py +200 -0
- fastapi_djauth-1.4.0/djauth/plantilla/.dockerignore.tpl +8 -0
- fastapi_djauth-1.4.0/djauth/plantilla/.env.example.tpl +15 -0
- fastapi_djauth-1.4.0/djauth/plantilla/.github/workflows/ci.yml.tpl +22 -0
- fastapi_djauth-1.4.0/djauth/plantilla/.gitignore.tpl +12 -0
- fastapi_djauth-1.4.0/djauth/plantilla/Dockerfile.tpl +26 -0
- fastapi_djauth-1.4.0/djauth/plantilla/README.md.tpl +83 -0
- fastapi_djauth-1.4.0/djauth/plantilla/alembic.ini.tpl +39 -0
- fastapi_djauth-1.4.0/djauth/plantilla/migrations/env.py.tpl +52 -0
- fastapi_djauth-1.4.0/djauth/plantilla/migrations/script.py.mako.tpl +24 -0
- fastapi_djauth-1.4.0/djauth/plantilla/migrations/versions/0001_productos.py.tpl +35 -0
- fastapi_djauth-1.4.0/djauth/plantilla/pyproject.toml.tpl +46 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/__init__.py.tpl +3 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/api/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/api/deps.py.tpl +12 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/api/router.py.tpl +8 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/api/v1/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/api/v1/productos.py.tpl +74 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/core/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/core/config.py.tpl +41 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/core/security.py.tpl +50 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/db.py.tpl +41 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/main.py.tpl +52 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/models/__init__.py.tpl +5 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/models/producto.py.tpl +24 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/schemas/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/schemas/producto.py.tpl +36 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/services/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/src/__paquete__/services/productos.py.tpl +46 -0
- fastapi_djauth-1.4.0/djauth/plantilla/tests/__init__.py.tpl +0 -0
- fastapi_djauth-1.4.0/djauth/plantilla/tests/conftest.py.tpl +35 -0
- fastapi_djauth-1.4.0/djauth/plantilla/tests/test_app.py.tpl +42 -0
- fastapi_djauth-1.4.0/djauth/py.typed +0 -0
- fastapi_djauth-1.4.0/djauth/routers.py +404 -0
- fastapi_djauth-1.4.0/djauth/settings.py +127 -0
- fastapi_djauth-1.4.0/djauth/startproject.py +271 -0
- fastapi_djauth-1.4.0/djauth/static/account.html +51 -0
- fastapi_djauth-1.4.0/djauth/static/account.js +34 -0
- fastapi_djauth-1.4.0/djauth/static/admin.html +167 -0
- fastapi_djauth-1.4.0/djauth/static/admin.js +346 -0
- fastapi_djauth-1.4.0/djauth/static/common.js +99 -0
- fastapi_djauth-1.4.0/djauth/static/djauth.css +99 -0
- fastapi_djauth-1.4.0/djauth/static/login.html +26 -0
- fastapi_djauth-1.4.0/djauth/static/login.js +38 -0
- fastapi_djauth-1.4.0/djauth/static/reset.html +27 -0
- fastapi_djauth-1.4.0/djauth/static/reset.js +30 -0
- fastapi_djauth-1.4.0/djauth/validators.py +139 -0
- fastapi_djauth-1.4.0/docs/01-instalacion.md +51 -0
- fastapi_djauth-1.4.0/docs/02-configuracion.md +107 -0
- fastapi_djauth-1.4.0/docs/03-proteger-rutas.md +131 -0
- fastapi_djauth-1.4.0/docs/04-sesion-y-bearer.md +54 -0
- fastapi_djauth-1.4.0/docs/05-usuarios-grupos-permisos.md +82 -0
- fastapi_djauth-1.4.0/docs/06-backends.md +83 -0
- fastapi_djauth-1.4.0/docs/07-extender-usuario.md +74 -0
- fastapi_djauth-1.4.0/docs/08-administracion.md +32 -0
- fastapi_djauth-1.4.0/docs/09-errores.md +78 -0
- fastapi_djauth-1.4.0/docs/10-seguridad.md +40 -0
- fastapi_djauth-1.4.0/docs/11-comandos.md +30 -0
- fastapi_djauth-1.4.0/docs/12-api.md +59 -0
- fastapi_djauth-1.4.0/docs/13-desde-django.md +63 -0
- fastapi_djauth-1.4.0/docs/14-historial-de-cambios.md +115 -0
- fastapi_djauth-1.4.0/docs/15-bases-de-datos.md +266 -0
- fastapi_djauth-1.4.0/docs/16-nuevo-proyecto.md +99 -0
- fastapi_djauth-1.4.0/docs/17-varias-bases-y-routers.md +194 -0
- fastapi_djauth-1.4.0/docs/README.md +23 -0
- fastapi_djauth-1.4.0/examples/app.py +41 -0
- fastapi_djauth-1.4.0/llms.txt +59 -0
- fastapi_djauth-1.4.0/pyproject.toml +82 -0
- fastapi_djauth-1.4.0/tests/test_backends_fields_errors.py +285 -0
- fastapi_djauth-1.4.0/tests/test_database.py +94 -0
- fastapi_djauth-1.4.0/tests/test_decorators.py +141 -0
- fastapi_djauth-1.4.0/tests/test_djauth.py +445 -0
- fastapi_djauth-1.4.0/tests/test_engines.py +122 -0
- fastapi_djauth-1.4.0/tests/test_routers.py +262 -0
- fastapi_djauth-1.4.0/tests/test_startproject.py +101 -0
- fastapi_djauth-1.4.0/tests/test_user_history.py +213 -0
- fastapi_djauth-1.4.0/tests/test_username_field.py +89 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Cambios
|
|
2
|
+
|
|
3
|
+
El formato sigue [Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y el proyecto usa [versionado semántico](https://semver.org/lang/es/).
|
|
4
|
+
|
|
5
|
+
## [1.4.0] - 2026-11-11
|
|
6
|
+
|
|
7
|
+
Primera versión publicada en PyPI.
|
|
8
|
+
|
|
9
|
+
### Corregido
|
|
10
|
+
- **MySQL, Oracle y SQL Server:** agregar columnas propias (`user_mixin`) a una tabla existente fallaba porque los nombres iban entre comillas dobles y se usaba `ADD COLUMN` en todos los motores. Ahora se usan las comillas y la sintaxis de cada motor.
|
|
11
|
+
- Un controlador asíncrono (`asyncpg`, `aiomysql`…) se rechaza al arrancar con un error claro, en lugar de fallar después. Ya no se elige `asyncpg` automáticamente.
|
|
12
|
+
- **Oracle** no funcionaba: las claves primarias no se generaban (ahora usan `IDENTITY`) y los textos vacíos fallaban, porque Oracle guarda `''` como NULL. Ahora esos textos admiten NULL solo en Oracle y se leen como `''`, igual que hace Django.
|
|
13
|
+
- Las claves primarias usan `IDENTITY` en PostgreSQL, Oracle y SQL Server para las tablas nuevas. Las tablas existentes no cambian.
|
|
14
|
+
|
|
15
|
+
### Cambiado
|
|
16
|
+
- Versión mínima de SQLAlchemy: 2.0.24, la primera que escapa `#` en las contraseñas al mostrar la URL de conexión.
|
|
17
|
+
- El paquete declara sus tipos (`py.typed`) y pasa `mypy`.
|
|
18
|
+
- Nuevos extras `mssql` (`pymssql`, sin dependencias del sistema) y `oracle` en las pistas de instalación.
|
|
19
|
+
|
|
20
|
+
### Añadido
|
|
21
|
+
- **Varias bases de datos y routers**, como `DATABASES` y `DATABASE_ROUTERS` de Django: `databases={...}` con alias, `database_routers=[...]` con `db_for_read`, `db_for_write`, `allow_relation` y `allow_migrate`, y `model._meta` con las mismas `app_label` de Django (los routers de Django funcionan tal cual). Sirve también para los modelos de la aplicación (`kit.databases`, `Databases`, `RoutingSession`). Ver [la guía](docs/17-varias-bases-y-routers.md).
|
|
22
|
+
- Seguros de las varias bases: alias `READ_ONLY` que nunca reciben escrituras; contraseñas, sesiones y tokens validados siempre en la base de escritura; lectura y escritura en la misma base dentro de una sesión de escritura; claves foráneas entre bases y alias desconocidos rechazados al arrancar; `allow_relation` comprobado antes de guardar.
|
|
23
|
+
- Guía de [bases de datos](docs/15-bases-de-datos.md): conexión y particularidades de cada motor.
|
|
24
|
+
- CI con Python 3.11 a 3.14 en Linux, Windows y macOS, versiones mínimas de las dependencias, PostgreSQL, MySQL, Oracle y SQL Server reales, `mypy`, `bandit` y `pip-audit`.
|
|
25
|
+
- `djauth startproject`: crea un proyecto FastAPI nuevo con arquitectura por capas, djauth integrado, Alembic, Docker, pruebas y CI; con las versiones probadas o las últimas. Ver [Nuevo proyecto](docs/16-nuevo-proyecto.md).
|
|
26
|
+
- Publicación automática en TestPyPI y PyPI con *Trusted Publishing* y atestaciones firmadas.
|
|
27
|
+
- `CONTRIBUTING.md`, plantillas de issues y de pull requests, Dependabot y `llms.txt`.
|
|
28
|
+
|
|
29
|
+
## [1.3.0] - 2026-11-11
|
|
30
|
+
|
|
31
|
+
### Añadido
|
|
32
|
+
- **Historial de cambios del usuario** (tabla `auth_user_history`): cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña (sin valores) y eliminación, con quién lo hizo, cuándo, desde qué IP y el motivo. Se guarda en la misma transacción que el cambio y se conserva al eliminar el usuario. Solo cambios del usuario: inicios de sesión y demás acciones siguen en el registro general.
|
|
33
|
+
- Rutas `GET /auth/api/user-history` y `GET /auth/api/users/{id}/history`, método `kit.user_history()` y permiso `auth.view_userchange`.
|
|
34
|
+
- Motivo del cambio: `?reason=` en la API, `reason=` en `create_user`, `update_user`, `delete_user` y `set_password`, y un campo en el formulario de la administración.
|
|
35
|
+
- Pestaña *Cambios de usuarios* en la administración.
|
|
36
|
+
- Campos sensibles: `info={"sensitive": True}` en columnas propias y `ExtraField(..., sensitive=True)` registran que cambiaron, sin los valores.
|
|
37
|
+
- Opción `user_history` para desactivarlo.
|
|
38
|
+
|
|
39
|
+
### Cambiado
|
|
40
|
+
- Los mensajes de error de la conexión a la base sugieren los nombres cortos de motor (`postgresql`, `mysql`…).
|
|
41
|
+
|
|
42
|
+
## [1.2.0] - 2026-11-10
|
|
43
|
+
|
|
44
|
+
### Añadido
|
|
45
|
+
- Decoradores `@login_required`, `@permission_required`, `@staff_member_required`, `@superuser_required` y `@user_passes_test`, además de las dependencias `current_user`, `require_perm`, etc.
|
|
46
|
+
|
|
47
|
+
### Cambiado
|
|
48
|
+
- Los ejemplos usan los nombres cortos de motor (`"ENGINE": "postgresql"`) y ya no dan a entender que hace falta Django. Los nombres de Django se siguen aceptando.
|
|
49
|
+
|
|
50
|
+
## [1.1.0] - 2026-11-10
|
|
51
|
+
|
|
52
|
+
### Añadido
|
|
53
|
+
- **Backends de autenticación** (`authentication_backends`), el equivalente de `AUTHENTICATION_BACKENDS` de Django: `ModelBackend`, `AllowAllUsersModelBackend` y `BaseBackend` para escribir los suyos (LDAP, otros sistemas, otras credenciales). Permisos sumados de todos los backends.
|
|
54
|
+
- **Extender el usuario con columnas reales** (`user_mixin`), como `AbstractUser`: aparecen en la API y en la administración, se leen como `user.campo`, y las columnas nuevas se agregan solas a la tabla.
|
|
55
|
+
- **Errores descriptivos**: todas las respuestas llevan `detail`, `code`, `hint` y `errors` por campo; los errores de formato se traducen al español (`422`).
|
|
56
|
+
- **`DATABASES` de Django** (`database={"ENGINE": …, "NAME": …}`): conexión sin escribir la URL, con contraseñas escapadas y elección automática del controlador instalado. Conexiones verificadas antes de usarse.
|
|
57
|
+
- **`username_field`**, el equivalente de `USERNAME_FIELD`: iniciar sesión con el usuario o con el correo (único, sin distinguir mayúsculas, garantizado por la base).
|
|
58
|
+
- Documentación por temas en `docs/`.
|
|
59
|
+
|
|
60
|
+
### Seguridad
|
|
61
|
+
- Un WebSocket autenticado con cookie debe abrirse desde el mismo origen (evita el secuestro de WebSocket entre sitios, CSWSH).
|
|
62
|
+
- Un administrador que no es superusuario ya no puede modificar ni cambiar la contraseña de usuarios con permisos que él no tiene.
|
|
63
|
+
- El inicio de sesión rechaza peticiones con `Origin` de otro sitio aunque aún no haya cookie.
|
|
64
|
+
- La cookie de sesión se marca `Secure` automáticamente cuando la petición llega por HTTPS.
|
|
65
|
+
|
|
66
|
+
## [1.0.0] - 2026-11-10
|
|
67
|
+
|
|
68
|
+
### Añadido
|
|
69
|
+
- Usuarios, grupos (roles) y permisos con el modelo de `django.contrib.auth`.
|
|
70
|
+
- Autenticación por sesión (cookie) o token Bearer opaco y revocable.
|
|
71
|
+
- Administración web, inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
|
|
72
|
+
- Contraseñas PBKDF2-SHA256 compatibles con Django.
|
|
73
|
+
- Comandos `createsuperuser`, `changepassword` y `listusers`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Contribuir a fastapi-djauth
|
|
2
|
+
|
|
3
|
+
Gracias por querer mejorar el paquete. Esta guía explica cómo preparar el entorno, qué se comprueba en cada cambio y cómo se publica una versión.
|
|
4
|
+
|
|
5
|
+
## Preparar el entorno
|
|
6
|
+
|
|
7
|
+
Requiere Python 3.11 o superior. Con [uv](https://docs.astral.sh/uv/) (recomendado):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/carlosvisbal/fastapi-djauth.git && cd fastapi-djauth
|
|
11
|
+
uv venv && uv pip install -e ".[test]"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
O con `pip`: `python -m venv .venv && . .venv/bin/activate && pip install -e ".[test]"`.
|
|
15
|
+
|
|
16
|
+
## Comprobaciones
|
|
17
|
+
|
|
18
|
+
Son las mismas que ejecuta la CI en cada pull request:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pytest # pruebas
|
|
22
|
+
uvx ruff check djauth tests examples # errores y estilo
|
|
23
|
+
uvx ruff format --check djauth tests examples # formato
|
|
24
|
+
uvx mypy # tipos
|
|
25
|
+
uvx bandit -q -r djauth # análisis de seguridad del código
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Contra PostgreSQL y MySQL reales
|
|
29
|
+
|
|
30
|
+
Las pruebas usan SQLite. `tests/test_engines.py` repite el flujo principal contra motores reales cuando se le indican:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
docker run -d --name pg -e POSTGRES_USER=djauth -e POSTGRES_PASSWORD=djauth -e POSTGRES_DB=djauth -p 5432:5432 postgres:17-alpine
|
|
34
|
+
docker run -d --name my -e MYSQL_ROOT_PASSWORD=root -e MYSQL_USER=djauth -e MYSQL_PASSWORD=djauth -e MYSQL_DATABASE=djauth -p 3306:3306 mysql:8.4
|
|
35
|
+
uv pip install -e ".[test,postgres,mysql]"
|
|
36
|
+
|
|
37
|
+
DJAUTH_TEST_DATABASE_URLS="postgresql+psycopg://djauth:djauth@127.0.0.1:5432/djauth mysql+pymysql://djauth:djauth@127.0.0.1:3306/djauth" \
|
|
38
|
+
pytest tests/test_engines.py -v
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Qué se espera de un cambio
|
|
42
|
+
|
|
43
|
+
- **Pruebas:** toda función nueva o error corregido lleva su prueba.
|
|
44
|
+
- **Documentación:** si cambia algo visible, actualice `docs/`, el README y `CHANGELOG.md` (sección "Sin publicar").
|
|
45
|
+
- **Idioma:** la documentación, los mensajes y los comentarios están en español.
|
|
46
|
+
- **Seguridad:** no se aceptan cambios que debiliten las protecciones por defecto (contraseñas, sesiones, CSRF, escalada de privilegios). Si su cambio toca autenticación, sesiones, permisos o datos personales, explique en el pull request su impacto en la seguridad.
|
|
47
|
+
- **Compatibilidad:** se sigue [versionado semántico](https://semver.org/lang/es/). Un cambio que rompa la API pública espera a la siguiente versión mayor.
|
|
48
|
+
|
|
49
|
+
Las fallas de seguridad **no** se informan en un issue: vea [SECURITY.md](SECURITY.md).
|
|
50
|
+
|
|
51
|
+
## Publicar una versión (mantenedores)
|
|
52
|
+
|
|
53
|
+
1. Actualice `__version__` en `djauth/__init__.py`. Es la única fuente de la versión.
|
|
54
|
+
2. Pase las notas de "Sin publicar" en `CHANGELOG.md` a la versión nueva, con la fecha.
|
|
55
|
+
3. Haga commit en `main` y espere a que la CI quede en verde.
|
|
56
|
+
4. Cree la Release en GitHub con la etiqueta `vX.Y.Z`:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gh release create vX.Y.Z --title "vX.Y.Z" --notes "Ver CHANGELOG.md"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
El flujo `publish.yml` comprueba que la etiqueta coincida con la versión y construye el paquete. Luego lo publica en TestPyPI y después en PyPI, este último con aprobación manual en el entorno `pypi`. Al final adjunta los archivos a la Release. No hacen falta contraseñas ni tokens (*Trusted Publishing*).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CARLOS DANIEL VISBAL ATENCIA
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: fastapi-djauth
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: Usuarios, roles, permisos y administración para FastAPI: sesión o token Bearer, seguro por defecto.
|
|
5
|
+
Project-URL: Homepage, https://github.com/carlosvisbal/fastapi-djauth
|
|
6
|
+
Project-URL: Documentation, https://github.com/carlosvisbal/fastapi-djauth/tree/main/docs
|
|
7
|
+
Project-URL: Changelog, https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/carlosvisbal/fastapi-djauth/issues
|
|
9
|
+
Project-URL: Source, https://github.com/carlosvisbal/fastapi-djauth
|
|
10
|
+
Project-URL: Security, https://github.com/carlosvisbal/fastapi-djauth/security/policy
|
|
11
|
+
Author: Carlos Daniel Visbal Atencia
|
|
12
|
+
Maintainer: Carlos Daniel Visbal Atencia
|
|
13
|
+
License-Expression: MIT
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Keywords: admin,audit,auth,authentication,authorization,bearer,django,fastapi,permissions,rbac,roles,session,users
|
|
16
|
+
Classifier: Development Status :: 4 - Beta
|
|
17
|
+
Classifier: Environment :: Web Environment
|
|
18
|
+
Classifier: Framework :: FastAPI
|
|
19
|
+
Classifier: Framework :: Pydantic :: 2
|
|
20
|
+
Classifier: Intended Audience :: Developers
|
|
21
|
+
Classifier: Natural Language :: Spanish
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
28
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Session
|
|
29
|
+
Classifier: Topic :: Security
|
|
30
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
31
|
+
Classifier: Typing :: Typed
|
|
32
|
+
Requires-Python: >=3.11
|
|
33
|
+
Requires-Dist: fastapi>=0.110
|
|
34
|
+
Requires-Dist: pydantic<3.0,>=2.5
|
|
35
|
+
Requires-Dist: sqlalchemy<3.0,>=2.0.24
|
|
36
|
+
Provides-Extra: mssql
|
|
37
|
+
Requires-Dist: pymssql>=2.3; extra == 'mssql'
|
|
38
|
+
Provides-Extra: mysql
|
|
39
|
+
Requires-Dist: pymysql[rsa]>=1.1; extra == 'mysql'
|
|
40
|
+
Provides-Extra: oracle
|
|
41
|
+
Requires-Dist: oracledb>=2.0; extra == 'oracle'
|
|
42
|
+
Provides-Extra: postgres
|
|
43
|
+
Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
|
|
44
|
+
Provides-Extra: test
|
|
45
|
+
Requires-Dist: httpx>=0.27; extra == 'test'
|
|
46
|
+
Requires-Dist: pytest>=8; extra == 'test'
|
|
47
|
+
Description-Content-Type: text/markdown
|
|
48
|
+
|
|
49
|
+
# fastapi-djauth
|
|
50
|
+
|
|
51
|
+
[](https://pypi.org/project/fastapi-djauth/)
|
|
52
|
+
[](https://pypi.org/project/fastapi-djauth/)
|
|
53
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml)
|
|
54
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/blob/main/pyproject.toml)
|
|
55
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE)
|
|
56
|
+
|
|
57
|
+
**Usuarios, roles, permisos y administración para FastAPI.** Sesión por cookie o token Bearer, una vista de administración lista, y la seguridad resuelta.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from fastapi import Depends, FastAPI
|
|
61
|
+
from djauth import AuthKit, AuthSettings, AuthUser, require_perm
|
|
62
|
+
|
|
63
|
+
kit = AuthKit(AuthSettings(
|
|
64
|
+
database={"ENGINE": "postgresql", "NAME": "miapp", "USER": "app", "PASSWORD": "…", "HOST": "localhost"},
|
|
65
|
+
permissions={"ventas": {"aprobar_pedido": "Puede aprobar pedidos"}},
|
|
66
|
+
)).init()
|
|
67
|
+
|
|
68
|
+
app = FastAPI()
|
|
69
|
+
|
|
70
|
+
@app.post("/pedidos/{id}/aprobar")
|
|
71
|
+
def aprobar(id: int, user: AuthUser = Depends(require_perm("ventas.aprobar_pedido"))):
|
|
72
|
+
return {"aprobado_por": user.username}
|
|
73
|
+
|
|
74
|
+
kit.install(app) # API en /auth/api y páginas: /auth/login, /auth/admin, /auth/account
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Qué trae
|
|
78
|
+
|
|
79
|
+
- **Usuarios, grupos (roles) y permisos** `app.codename`, con `user.has_perm()`, decoradores (`@login_required`, `@permission_required`) o dependencias.
|
|
80
|
+
- **Configurable sin código extra:** conexión a la base por diccionario, inicio de sesión con usuario o con correo, backends de autenticación propios (LDAP, otros sistemas) y columnas propias en el usuario.
|
|
81
|
+
- **Sesión o Bearer:** cookie `HttpOnly` para navegadores, tokens opacos y revocables para APIs; uno, otro o los dos.
|
|
82
|
+
- **Administración web:** usuarios, grupos, permisos y registro de acciones; inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
|
|
83
|
+
- **Historial de cambios del usuario:** cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña y baja, con quién, cuándo, desde qué IP y por qué. Nunca guarda contraseñas.
|
|
84
|
+
- **Seguro por defecto:** contraseñas PBKDF2-SHA256, bloqueo por fuerza bruta, CSRF, protección de WebSocket, sin escalada de privilegios entre administradores, cabeceras de seguridad.
|
|
85
|
+
- **Errores descriptivos:** cada error trae mensaje, código fijo, campo afectado y cómo resolverlo.
|
|
86
|
+
- **Cualquier base:** SQLite, PostgreSQL, MySQL/MariaDB, Oracle o SQL Server (SQLAlchemy 2), probadas contra servidores reales en cada cambio.
|
|
87
|
+
- **Varias bases y routers:** `databases` y `database_routers`, como `DATABASES` y `DATABASE_ROUTERS` de Django: réplicas de lectura o una base por área, también para sus propios modelos.
|
|
88
|
+
- **Plantilla de proyecto:** `djauth startproject` crea una aplicación nueva lista para producción.
|
|
89
|
+
|
|
90
|
+
## Proyecto nuevo en un minuto
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install fastapi-djauth
|
|
94
|
+
djauth startproject inventario --db postgresql
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Crea una aplicación FastAPI completa con arquitectura por capas, usuarios y permisos, Alembic, Docker, pruebas y CI. Usted elige las versiones probadas o las últimas de cada librería. Ver [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md).
|
|
98
|
+
|
|
99
|
+
## Instalación
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pip install fastapi-djauth # PyPI
|
|
103
|
+
pip install "fastapi-djauth[postgres]" # con el controlador de PostgreSQL
|
|
104
|
+
pip install "git+https://github.com/carlosvisbal/fastapi-djauth.git" # última versión de GitHub
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Requiere Python 3.11+.
|
|
108
|
+
|
|
109
|
+
## Documentación
|
|
110
|
+
|
|
111
|
+
| | |
|
|
112
|
+
|---|---|
|
|
113
|
+
| **Empezar** | [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md) · [Instalación y primer uso](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/01-instalacion.md) · [Configuración](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/02-configuracion.md) · [Bases de datos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/15-bases-de-datos.md) · [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md) |
|
|
114
|
+
| **Usar** | [Proteger rutas](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/03-proteger-rutas.md) · [Sesión o Bearer](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/04-sesion-y-bearer.md) · [Usuarios, grupos y permisos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/05-usuarios-grupos-permisos.md) |
|
|
115
|
+
| **Personalizar** | [Varias bases y routers](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/17-varias-bases-y-routers.md) · [Backends de autenticación](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/06-backends.md) · [Extender el usuario](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/07-extender-usuario.md) |
|
|
116
|
+
| **Operar** | [Administración web](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/08-administracion.md) · [Historial de cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/14-historial-de-cambios.md) · [Comandos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/11-comandos.md) · [Seguridad](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) |
|
|
117
|
+
| **Referencia** | [API REST](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/12-api.md) · [Errores](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/09-errores.md) · [Cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md) |
|
|
118
|
+
|
|
119
|
+
¿Viene de Django? Los conceptos y la configuración le resultarán familiares, y puede importar sus usuarios con su contraseña: vea [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md). El paquete **no** necesita Django instalado.
|
|
120
|
+
|
|
121
|
+
Hay un ejemplo completo en [examples/app.py](https://github.com/carlosvisbal/fastapi-djauth/blob/main/examples/app.py).
|
|
122
|
+
|
|
123
|
+
## Seguridad
|
|
124
|
+
|
|
125
|
+
Lea [docs/10-seguridad.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) antes de poner el servicio en producción. Para informar una vulnerabilidad, use el aviso privado de GitHub ([SECURITY.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/SECURITY.md)), no un issue público.
|
|
126
|
+
|
|
127
|
+
## Contribuir
|
|
128
|
+
|
|
129
|
+
Las contribuciones son bienvenidas. Vea [CONTRIBUTING.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CONTRIBUTING.md): cómo preparar el entorno, las pruebas (también contra PostgreSQL y MySQL reales) y el proceso de publicación.
|
|
130
|
+
|
|
131
|
+
## Licencia
|
|
132
|
+
|
|
133
|
+
[MIT](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE) © Carlos Daniel Visbal Atencia
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# fastapi-djauth
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/fastapi-djauth/)
|
|
4
|
+
[](https://pypi.org/project/fastapi-djauth/)
|
|
5
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/blob/main/pyproject.toml)
|
|
7
|
+
[](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
**Usuarios, roles, permisos y administración para FastAPI.** Sesión por cookie o token Bearer, una vista de administración lista, y la seguridad resuelta.
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from fastapi import Depends, FastAPI
|
|
13
|
+
from djauth import AuthKit, AuthSettings, AuthUser, require_perm
|
|
14
|
+
|
|
15
|
+
kit = AuthKit(AuthSettings(
|
|
16
|
+
database={"ENGINE": "postgresql", "NAME": "miapp", "USER": "app", "PASSWORD": "…", "HOST": "localhost"},
|
|
17
|
+
permissions={"ventas": {"aprobar_pedido": "Puede aprobar pedidos"}},
|
|
18
|
+
)).init()
|
|
19
|
+
|
|
20
|
+
app = FastAPI()
|
|
21
|
+
|
|
22
|
+
@app.post("/pedidos/{id}/aprobar")
|
|
23
|
+
def aprobar(id: int, user: AuthUser = Depends(require_perm("ventas.aprobar_pedido"))):
|
|
24
|
+
return {"aprobado_por": user.username}
|
|
25
|
+
|
|
26
|
+
kit.install(app) # API en /auth/api y páginas: /auth/login, /auth/admin, /auth/account
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Qué trae
|
|
30
|
+
|
|
31
|
+
- **Usuarios, grupos (roles) y permisos** `app.codename`, con `user.has_perm()`, decoradores (`@login_required`, `@permission_required`) o dependencias.
|
|
32
|
+
- **Configurable sin código extra:** conexión a la base por diccionario, inicio de sesión con usuario o con correo, backends de autenticación propios (LDAP, otros sistemas) y columnas propias en el usuario.
|
|
33
|
+
- **Sesión o Bearer:** cookie `HttpOnly` para navegadores, tokens opacos y revocables para APIs; uno, otro o los dos.
|
|
34
|
+
- **Administración web:** usuarios, grupos, permisos y registro de acciones; inicio de sesión, "Mi cuenta" y restablecimiento de contraseña.
|
|
35
|
+
- **Historial de cambios del usuario:** cada alta, modificación (valor anterior y nuevo por campo), cambio de contraseña y baja, con quién, cuándo, desde qué IP y por qué. Nunca guarda contraseñas.
|
|
36
|
+
- **Seguro por defecto:** contraseñas PBKDF2-SHA256, bloqueo por fuerza bruta, CSRF, protección de WebSocket, sin escalada de privilegios entre administradores, cabeceras de seguridad.
|
|
37
|
+
- **Errores descriptivos:** cada error trae mensaje, código fijo, campo afectado y cómo resolverlo.
|
|
38
|
+
- **Cualquier base:** SQLite, PostgreSQL, MySQL/MariaDB, Oracle o SQL Server (SQLAlchemy 2), probadas contra servidores reales en cada cambio.
|
|
39
|
+
- **Varias bases y routers:** `databases` y `database_routers`, como `DATABASES` y `DATABASE_ROUTERS` de Django: réplicas de lectura o una base por área, también para sus propios modelos.
|
|
40
|
+
- **Plantilla de proyecto:** `djauth startproject` crea una aplicación nueva lista para producción.
|
|
41
|
+
|
|
42
|
+
## Proyecto nuevo en un minuto
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install fastapi-djauth
|
|
46
|
+
djauth startproject inventario --db postgresql
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Crea una aplicación FastAPI completa con arquitectura por capas, usuarios y permisos, Alembic, Docker, pruebas y CI. Usted elige las versiones probadas o las últimas de cada librería. Ver [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md).
|
|
50
|
+
|
|
51
|
+
## Instalación
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install fastapi-djauth # PyPI
|
|
55
|
+
pip install "fastapi-djauth[postgres]" # con el controlador de PostgreSQL
|
|
56
|
+
pip install "git+https://github.com/carlosvisbal/fastapi-djauth.git" # última versión de GitHub
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Requiere Python 3.11+.
|
|
60
|
+
|
|
61
|
+
## Documentación
|
|
62
|
+
|
|
63
|
+
| | |
|
|
64
|
+
|---|---|
|
|
65
|
+
| **Empezar** | [Proyecto nuevo](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/16-nuevo-proyecto.md) · [Instalación y primer uso](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/01-instalacion.md) · [Configuración](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/02-configuracion.md) · [Bases de datos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/15-bases-de-datos.md) · [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md) |
|
|
66
|
+
| **Usar** | [Proteger rutas](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/03-proteger-rutas.md) · [Sesión o Bearer](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/04-sesion-y-bearer.md) · [Usuarios, grupos y permisos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/05-usuarios-grupos-permisos.md) |
|
|
67
|
+
| **Personalizar** | [Varias bases y routers](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/17-varias-bases-y-routers.md) · [Backends de autenticación](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/06-backends.md) · [Extender el usuario](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/07-extender-usuario.md) |
|
|
68
|
+
| **Operar** | [Administración web](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/08-administracion.md) · [Historial de cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/14-historial-de-cambios.md) · [Comandos](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/11-comandos.md) · [Seguridad](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) |
|
|
69
|
+
| **Referencia** | [API REST](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/12-api.md) · [Errores](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/09-errores.md) · [Cambios](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CHANGELOG.md) |
|
|
70
|
+
|
|
71
|
+
¿Viene de Django? Los conceptos y la configuración le resultarán familiares, y puede importar sus usuarios con su contraseña: vea [Desde Django](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/13-desde-django.md). El paquete **no** necesita Django instalado.
|
|
72
|
+
|
|
73
|
+
Hay un ejemplo completo en [examples/app.py](https://github.com/carlosvisbal/fastapi-djauth/blob/main/examples/app.py).
|
|
74
|
+
|
|
75
|
+
## Seguridad
|
|
76
|
+
|
|
77
|
+
Lea [docs/10-seguridad.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/docs/10-seguridad.md) antes de poner el servicio en producción. Para informar una vulnerabilidad, use el aviso privado de GitHub ([SECURITY.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/SECURITY.md)), no un issue público.
|
|
78
|
+
|
|
79
|
+
## Contribuir
|
|
80
|
+
|
|
81
|
+
Las contribuciones son bienvenidas. Vea [CONTRIBUTING.md](https://github.com/carlosvisbal/fastapi-djauth/blob/main/CONTRIBUTING.md): cómo preparar el entorno, las pruebas (también contra PostgreSQL y MySQL reales) y el proceso de publicación.
|
|
82
|
+
|
|
83
|
+
## Licencia
|
|
84
|
+
|
|
85
|
+
[MIT](https://github.com/carlosvisbal/fastapi-djauth/blob/main/LICENSE) © Carlos Daniel Visbal Atencia
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Política de seguridad
|
|
2
|
+
|
|
3
|
+
## Versiones con soporte
|
|
4
|
+
|
|
5
|
+
| Versión | Soporte |
|
|
6
|
+
|---|---|
|
|
7
|
+
| 1.3.x | Sí |
|
|
8
|
+
| < 1.3 | No: actualice a la última versión (1.1.0 corrigió el secuestro de WebSocket entre sitios) |
|
|
9
|
+
|
|
10
|
+
## Informar una vulnerabilidad
|
|
11
|
+
|
|
12
|
+
**No abra un issue público.** Use el aviso privado de GitHub: pestaña **Security → Report a vulnerability** en https://github.com/carlosvisbal/fastapi-djauth/security/advisories/new
|
|
13
|
+
|
|
14
|
+
Incluya, si puede: versión afectada, pasos para reproducirlo y el impacto. Recibirá respuesta en un plazo de 7 días. Una vez corregido, se publica una versión nueva y un aviso con el crédito a quien lo informó (si lo desea).
|
|
15
|
+
|
|
16
|
+
Lo que protege el módulo y sus límites: [docs/10-seguridad.md](docs/10-seguridad.md).
|
|
17
|
+
|
|
18
|
+
## Cómo se protege la cadena de publicación
|
|
19
|
+
|
|
20
|
+
- Los paquetes se publican desde GitHub Actions con *Trusted Publishing*: no existen contraseñas ni tokens de PyPI que robar.
|
|
21
|
+
- Cada versión en PyPI lleva una atestación firmada (PEP 740) que prueba de qué repositorio y flujo salió.
|
|
22
|
+
- Las acciones de GitHub están fijadas por commit, y Dependabot propone sus actualizaciones.
|
|
23
|
+
- En cada cambio se ejecutan pruebas, análisis de tipos (`mypy`), análisis de seguridad del código (`bandit`) y la búsqueda de vulnerabilidades conocidas en las dependencias (`pip-audit`).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""djauth: usuarios, grupos (roles), permisos y administración al estilo de Django, para FastAPI.
|
|
2
|
+
|
|
3
|
+
from djauth import AuthKit, AuthSettings, current_user, require_perm
|
|
4
|
+
|
|
5
|
+
kit = AuthKit(AuthSettings(database_url="sqlite:///auth.sqlite3")).init()
|
|
6
|
+
kit.install(app, protect=True)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from djauth.api import (
|
|
10
|
+
AuthMiddleware,
|
|
11
|
+
Rule,
|
|
12
|
+
current_user,
|
|
13
|
+
identify,
|
|
14
|
+
optional_user,
|
|
15
|
+
require_perm,
|
|
16
|
+
require_staff,
|
|
17
|
+
require_superuser,
|
|
18
|
+
rule,
|
|
19
|
+
ws_user,
|
|
20
|
+
)
|
|
21
|
+
from djauth.backends import AllowAllUsersModelBackend, AuthRequest, BaseBackend, ModelBackend
|
|
22
|
+
from djauth.core import SERVICE_USER, AuthKit, AuthUser
|
|
23
|
+
from djauth.database import DatabaseConfigError, url_from_django
|
|
24
|
+
from djauth.decorators import login_required, permission_required, staff_member_required, superuser_required, user_passes_test
|
|
25
|
+
from djauth.errors import (
|
|
26
|
+
AuthError,
|
|
27
|
+
InvalidCredentialsError,
|
|
28
|
+
NotAuthenticatedError,
|
|
29
|
+
NotFoundError,
|
|
30
|
+
PermissionDeniedError,
|
|
31
|
+
TooManyAttemptsError,
|
|
32
|
+
ValidationError,
|
|
33
|
+
)
|
|
34
|
+
from djauth.hashers import check_password, make_password
|
|
35
|
+
from djauth.routers import BaseRouter, Databases, ModelMeta, RoutingSession, model_meta
|
|
36
|
+
from djauth.settings import AuthSettings, ExtraField
|
|
37
|
+
|
|
38
|
+
__version__ = "1.4.0"
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"SERVICE_USER",
|
|
42
|
+
"AllowAllUsersModelBackend",
|
|
43
|
+
"AuthError",
|
|
44
|
+
"AuthKit",
|
|
45
|
+
"AuthMiddleware",
|
|
46
|
+
"AuthRequest",
|
|
47
|
+
"AuthSettings",
|
|
48
|
+
"AuthUser",
|
|
49
|
+
"BaseBackend",
|
|
50
|
+
"BaseRouter",
|
|
51
|
+
"DatabaseConfigError",
|
|
52
|
+
"Databases",
|
|
53
|
+
"ExtraField",
|
|
54
|
+
"InvalidCredentialsError",
|
|
55
|
+
"ModelBackend",
|
|
56
|
+
"ModelMeta",
|
|
57
|
+
"NotAuthenticatedError",
|
|
58
|
+
"NotFoundError",
|
|
59
|
+
"PermissionDeniedError",
|
|
60
|
+
"RoutingSession",
|
|
61
|
+
"Rule",
|
|
62
|
+
"TooManyAttemptsError",
|
|
63
|
+
"ValidationError",
|
|
64
|
+
"__version__",
|
|
65
|
+
"check_password",
|
|
66
|
+
"current_user",
|
|
67
|
+
"identify",
|
|
68
|
+
"login_required",
|
|
69
|
+
"make_password",
|
|
70
|
+
"model_meta",
|
|
71
|
+
"optional_user",
|
|
72
|
+
"permission_required",
|
|
73
|
+
"require_perm",
|
|
74
|
+
"require_staff",
|
|
75
|
+
"require_superuser",
|
|
76
|
+
"rule",
|
|
77
|
+
"staff_member_required",
|
|
78
|
+
"superuser_required",
|
|
79
|
+
"url_from_django",
|
|
80
|
+
"user_passes_test",
|
|
81
|
+
"ws_user",
|
|
82
|
+
]
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Comandos de administración (como `manage.py`):
|
|
2
|
+
|
|
3
|
+
python -m djauth --db sqlite:///auth.sqlite3 createsuperuser --username admin --email a@b.co
|
|
4
|
+
python -m djauth --db … changepassword admin
|
|
5
|
+
python -m djauth --db … listusers
|
|
6
|
+
djauth startproject inventario --db postgresql # proyecto FastAPI nuevo con djauth integrado
|
|
7
|
+
|
|
8
|
+
La contraseña se pide por teclado; para scripts, use la variable DJAUTH_PASSWORD.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import getpass
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
|
|
18
|
+
from djauth.core import AuthKit
|
|
19
|
+
from djauth.errors import AuthError, ValidationError
|
|
20
|
+
from djauth.settings import AuthSettings
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _ask_password() -> str:
|
|
24
|
+
if env := os.environ.get("DJAUTH_PASSWORD"):
|
|
25
|
+
return env
|
|
26
|
+
while True:
|
|
27
|
+
first = getpass.getpass("Contraseña: ")
|
|
28
|
+
if first == getpass.getpass("Contraseña (otra vez): "):
|
|
29
|
+
return first
|
|
30
|
+
print("Las contraseñas no coinciden.", file=sys.stderr)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main(argv: list[str] | None = None) -> int:
|
|
34
|
+
parser = argparse.ArgumentParser(prog="python -m djauth", description="Administración de usuarios de djauth")
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--db", default=os.environ.get("DJAUTH_DATABASE_URL", "sqlite:///auth.sqlite3"), help="URL de la base de datos"
|
|
37
|
+
)
|
|
38
|
+
parser.add_argument("--prefix", default="auth_", help="Prefijo de las tablas")
|
|
39
|
+
sub = parser.add_subparsers(dest="command", required=True)
|
|
40
|
+
create = sub.add_parser("createsuperuser", help="Crear un superusuario")
|
|
41
|
+
create.add_argument("--username", required=True)
|
|
42
|
+
create.add_argument("--email", default="")
|
|
43
|
+
change = sub.add_parser("changepassword", help="Cambiar la contraseña de un usuario")
|
|
44
|
+
change.add_argument("username")
|
|
45
|
+
sub.add_parser("listusers", help="Listar usuarios")
|
|
46
|
+
start = sub.add_parser("startproject", help="Crear un proyecto FastAPI nuevo con djauth integrado")
|
|
47
|
+
start.add_argument("name", help="Nombre del paquete: minúsculas, números y _ (p. ej. inventario)")
|
|
48
|
+
start.add_argument("directory", nargs="?", help="Carpeta donde crearlo (por defecto ./<name>; debe estar vacía)")
|
|
49
|
+
start.add_argument("--db", dest="db_engine", choices=("sqlite", "postgresql", "mysql"), default="sqlite")
|
|
50
|
+
start.add_argument(
|
|
51
|
+
"--versiones",
|
|
52
|
+
dest="versions",
|
|
53
|
+
choices=("probadas", "ultimas"),
|
|
54
|
+
default="probadas",
|
|
55
|
+
help="probadas: versiones exactas verificadas con este djauth · ultimas: lo más reciente compatible",
|
|
56
|
+
)
|
|
57
|
+
start.add_argument("--titulo", dest="title", help='Nombre visible de la aplicación (p. ej. "Inventario de planta")')
|
|
58
|
+
start.add_argument("--sin-lock", dest="no_lock", action="store_true", help="No ejecutar `uv lock` al terminar")
|
|
59
|
+
args = parser.parse_args(argv)
|
|
60
|
+
|
|
61
|
+
if args.command == "startproject":
|
|
62
|
+
from djauth.startproject import main as startproject
|
|
63
|
+
|
|
64
|
+
return startproject(args)
|
|
65
|
+
|
|
66
|
+
kit = AuthKit(AuthSettings(database_url=args.db, table_prefix=args.prefix)).init()
|
|
67
|
+
try:
|
|
68
|
+
if args.command == "createsuperuser":
|
|
69
|
+
created = kit.create_superuser(
|
|
70
|
+
args.username, _ask_password(), email=args.email, reason="Creado con djauth createsuperuser."
|
|
71
|
+
)
|
|
72
|
+
print(f"Superusuario {created['username']} creado.")
|
|
73
|
+
elif args.command == "changepassword":
|
|
74
|
+
user = kit.get_by_username(args.username)
|
|
75
|
+
if user is None:
|
|
76
|
+
print(f"No existe el usuario {args.username}.", file=sys.stderr)
|
|
77
|
+
return 1
|
|
78
|
+
kit.set_password(user.id, _ask_password(), reason="Cambiada con djauth changepassword.")
|
|
79
|
+
print(f"Contraseña de {user.username} cambiada; sus sesiones abiertas se cerraron.")
|
|
80
|
+
elif args.command == "listusers":
|
|
81
|
+
items, total = kit.list_users(limit=1000)
|
|
82
|
+
for u in items:
|
|
83
|
+
flags = "".join(f for f, on in (("S", u["is_superuser"]), ("A", u["is_staff"]), ("-", not u["is_active"])) if on)
|
|
84
|
+
print(f"{u['id']:>5} {u['username']:<30} {flags:<3} {', '.join(u['groups'])}")
|
|
85
|
+
print(f"{total} usuarios")
|
|
86
|
+
except ValidationError as exc:
|
|
87
|
+
for field, messages in exc.errors.items():
|
|
88
|
+
for m in messages:
|
|
89
|
+
print(f"{field}: {m}", file=sys.stderr)
|
|
90
|
+
return 1
|
|
91
|
+
except AuthError as exc:
|
|
92
|
+
print(str(exc), file=sys.stderr)
|
|
93
|
+
return 1
|
|
94
|
+
return 0
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == "__main__":
|
|
98
|
+
raise SystemExit(main())
|