Étape 8 : connexion par mot de passe pour la coordination
Deux systèmes d'authentification, une même session JWT :
- COORDINATION : login e-mail + mot de passe (bcrypt), POST .../auth/login ;
POST .../auth/change-password pour le compte courant
- RÉFÉRENTS / BÉNÉVOLES : lien magique inchangé, mais refusé pour un compte
qui a un mot de passe
- Account.password_hash (nullable) + migration 0002 ; propriété auth_method
("password" / "magic_link") exposée dans AccountRead
- app/auth/passwords.py : hash/verify bcrypt, longueur mini 10
- Création de compte : password requis pour COORDINATOR, interdit sinon
- seed : la coordination de démo a un mot de passe, affiché dans le résumé
- 12 tests (login ok/ko, séparation des deux systèmes, change-password,
validation à la création) ; 129 tests au total ; alembic check vert
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
1f9f460540
commit
8a879ca5c3
@@ -24,11 +24,11 @@ def test_magic_link_unknown_email_is_accepted_without_token(
|
||||
def test_full_flow_magic_link_then_jwt_then_me(
|
||||
raw_client, session, edition, make_account, caplog
|
||||
):
|
||||
make_account(Role.COORDINATOR, email="coord@example.fr")
|
||||
make_account(Role.LEAD, email="ref@example.fr")
|
||||
|
||||
with caplog.at_level(logging.INFO, logger="app.auth"):
|
||||
resp = raw_client.post(
|
||||
_url(edition, "magic-link"), json={"email": "COORD@example.fr"}
|
||||
_url(edition, "magic-link"), json={"email": "REF@example.fr"}
|
||||
)
|
||||
assert resp.status_code == 202
|
||||
log_line = next(m for m in caplog.messages if "STUB lien magique" in m)
|
||||
@@ -40,14 +40,15 @@ def test_full_flow_magic_link_then_jwt_then_me(
|
||||
assert verified.status_code == 200
|
||||
body = verified.json()
|
||||
assert body["token_type"] == "bearer"
|
||||
assert body["account"]["role"] == "COORDINATOR"
|
||||
assert body["account"]["role"] == "LEAD"
|
||||
assert body["account"]["auth_method"] == "magic_link"
|
||||
|
||||
me = raw_client.get(
|
||||
"/auth/me",
|
||||
headers={"Authorization": f"Bearer {body['access_token']}"},
|
||||
)
|
||||
assert me.status_code == 200
|
||||
assert me.json()["email"] == "coord@example.fr"
|
||||
assert me.json()["email"] == "ref@example.fr"
|
||||
|
||||
|
||||
def test_verify_is_single_use(raw_client, session, edition, make_account):
|
||||
|
||||
Reference in New Issue
Block a user