Développement #69221
backend authn : faire que le backend login/mot de passe accepte le numéro de téléphone de l’usager
0%
Description
Du code déjà présent en partie dans #65173, que je dois déplacer ici et accompagner de davantage de tests, diviser pour mieux régner etc.
Files
Related issues
Associated revisions
History
Updated by Paul Marillonnet about 2 years ago
- Related to Développement #49212: Création de compte avec un numéro de téléphone mobile added
Updated by Paul Marillonnet about 2 years ago
- Status changed from Nouveau to En cours
- Assignee set to Paul Marillonnet
Updated by Paul Marillonnet about 2 years ago
- File 0001-authentication-forms-add-user-phone-as-identifier-69.patch 0001-authentication-forms-add-user-phone-as-identifier-69.patch added
- Status changed from En cours to Solution proposée
- Patch proposed changed from No to Yes
La version au plus simple, qui ne nécessite pas de revoir complètement la façon dont on utilise le ModelBackend de Django. Le prix à payer pour ça est encore un peu de magie dans authentic2.forms.authentication.AuthenticationForm
. Je pense que ça reste préférable.
Bien sûr en l’état l’affichage est moche, aucune aide à la sélection entre numéro de tél ou username/email, aucune aide à la saisie du numéro ni au choix du préfixe, aucune validation front de ce numéro -> tout ça c’est l’objet du ticket voisin #69222, que je m’empresse d’aller étudier là maintenant :)
Updated by A. B. about 2 years ago
Ça me parait top, une question : je vois qu'on concatène le phone_prefix et le numéro de téléphone pour construire l'identifiant pour la requête. Ça risque pas de bugger sur des inputs type 0612345678 (avec la concaténation, on aura un +330612345678), à matcher avec potentiellement un +33612345678, sans le zéro ? Il me semble qu'un·e utilisateur aura tendance à taper son numéro avec le 0 comme préfixe mais je peux me tromper.
Plus généralement, peut-être que ça a été déjà discuté ailleurs, comment se passe la normalisation des numéros avant stockage en base ?
À part ces questions, c'est okay pour moi :)
Updated by Thomas Noël about 2 years ago
Agate Berriot a écrit :
Ça me parait top, une question : je vois qu'on concatène le phone_prefix et le numéro de téléphone pour construire l'identifiant pour la requête. Ça risque pas de bugger sur des inputs type 0612345678 (avec la concaténation, on aura un +330612345678), à matcher avec potentiellement un +33612345678, sans le zéro ? Il me semble qu'un·e utilisateur aura tendance à taper son numéro avec le 0 comme préfixe mais je peux me tromper.
Agate a raison... bienvenue en enfer, Paul ;)
Je vais ajouter qu'il faut ajouter dans les settings les préfixes des DROM, qui font partie du https://fr.wikipedia.org/wiki/Plan_de_num%C3%A9rotation_en_France (bonne lecture).
Updated by Paul Marillonnet about 2 years ago
Agate Berriot a écrit :
Ça me parait top, une question : je vois qu'on concatène le phone_prefix et le numéro de téléphone pour construire l'identifiant pour la requête. Ça risque pas de bugger sur des inputs type 0612345678 (avec la concaténation, on aura un +330612345678), à matcher avec potentiellement un +33612345678, sans le zéro ? Il me semble qu'un·e utilisateur aura tendance à taper son numéro avec le 0 comme préfixe mais je peux me tromper.
Je m’imaginais faire d’abord un truc qui marche pour les numéros français, avec dans #69222 une aide à la saisie lorsque le préfixe français est sélectionné (par exemple en isolant le premier chiffre puis en regroupant deux par deux les huit chiffres suivants, afin que l’usager capte bien que le zéro initial saute). Mais j’ai zappé ce que Thomas met ici et donc il me faut revoir ma copie :)
Sans cette hypothèse, j’avoue que je ne sais pas trop de quelle façon on peut restreindre davantage ici, notamment parce que https://en.wikipedia.org/wiki/Telephone_numbers_in_Belgium, page à laquelle je ne comprends rien :)
Plus généralement, peut-être que ça a été déjà discuté ailleurs, comment se passe la normalisation des numéros avant stockage en base ?
Non, pas discuté ailleurs, et ici et maintenant peut être l’occasion d’en discuter. J’avais en tête de faire dans #69222 un maximum de sanitization de l’input en front, pour réduire au maximum les écarts entre les données collectées par le formulaire et la version stockée en base. Typiquement juste une suite de chiffres sans le zéro initial, qu’on pourrait vérifier facilement ensuite sans normalisation à proprement parler. J’avais peur qu’à tolérer de trop grands écarts on loupe des choses à la normalisation, genre l’usager qui tape un caractère d’espacement exotique (espace semi-fine insécable " ", tirets typographiques "–" ou encore "—", etc.) qui casserait toute l’affaire. Mais peut-être cette approche est une mauvaise idée, on peut en discuter ici.
À part ces questions, c'est okay pour moi :)
Cool, merci pour ta relecture. Je vais avancer sur les autres tickets liés à #49212 pour pouvoir proposer une démo complète avant qu’on envisage passer tous ces patches.
Updated by A. B. about 2 years ago
Thomas Noël a écrit :
Agate Berriot a écrit :
Ça me parait top, une question : je vois qu'on concatène le phone_prefix et le numéro de téléphone pour construire l'identifiant pour la requête. Ça risque pas de bugger sur des inputs type 0612345678 (avec la concaténation, on aura un +330612345678), à matcher avec potentiellement un +33612345678, sans le zéro ? Il me semble qu'un·e utilisateur aura tendance à taper son numéro avec le 0 comme préfixe mais je peux me tromper.
Agate a raison... bienvenue en enfer, Paul ;)
Je vais ajouter qu'il faut ajouter dans les settings les préfixes des DROM, qui font partie du https://fr.wikipedia.org/wiki/Plan_de_num%C3%A9rotation_en_France (bonne lecture).
Pour moi la solution durable, c'est de prendre une bibliothèque type https://pypi.org/project/phonenumbers/#description et tout normaliser via ce biais avant de stocker ou faire des comparaisons. Ça nous permettra de gérer du même coup les espaces, tirets, tous les formats un peu chelous avec les parenthèses, les préfixes avec + ou les doubles 00. Surtout si on commence à accepter des numéros d'autres pays ou de territoires avec des préfixes ou des structures différentes et qu'on bricole un truc maison, ça va être ingérable.
Updated by Paul Marillonnet about 2 years ago
Agate Berriot a écrit :
Pour moi la solution durable, c'est de prendre une bibliothèque type https://pypi.org/project/phonenumbers/#description et tout normaliser via ce biais avant de stocker ou faire des comparaisons. Ça nous permettra de gérer du même coup les espaces, tirets, tous les formats un peu chelous avec les parenthèses, les préfixes avec + ou les doubles 00. Surtout si on commence à accepter des numéros d'autres pays ou de territoires avec des préfixes ou des structures différentes et qu'on bricole un truc maison, ça va être ingérable.
Oui, sûr, surtout ne rien bricoler. Je vais regarder cette bibliothèque, déjà empaquetée dans Debian. Je note aussi que des gens ont fait le taff d’intégration directe de cette bibliothèque nativement dans Django, ça donne https://django-phonenumber-field.readthedocs.io/en/latest/, ça a l’air maintenu et c’est aussi disponible dans les dépôts standards Debian.
Updated by Paul Marillonnet about 2 years ago
Paul Marillonnet a écrit :
[…] Je note aussi que des gens ont fait le taff d’intégration directe de cette bibliothèque nativement dans Django, ça donne https://django-phonenumber-field.readthedocs.io/en/latest/, ça a l’air maintenu et c’est aussi disponible dans les dépôts standards Debian.
Et non, raté, packagé que dans sid.
Updated by Frédéric Péters about 2 years ago
Et non, raté, packagé que dans sid.
Pas un gros problème ça.
Updated by Paul Marillonnet about 2 years ago
Frédéric Péters a écrit :
Pas un gros problème ça.
Ok, noté, je regarde plus en détails.
Updated by Benjamin Dauvergne about 2 years ago
Thomas Noël a écrit :
Je vais ajouter qu'il faut ajouter dans les settings les préfixes des DROM, qui font partie du https://fr.wikipedia.org/wiki/Plan_de_num%C3%A9rotation_en_France (bonne lecture).
Ça dit :
Tous les correspondants du territoire national (métropole ou DOM) peuvent s'appeler entre eux en utilisant le plan de numérotation français à dix chiffres, sans composer le code pays pour la voix, les SMS et les MMS. À Saint-Pierre-et-Miquelon, les abonnés peuvent se joindre en composant les six derniers chiffres de leurs numéros.
je pense que les numéros mobiles sont exposés sur les toutes les indicatifs nationaux du plan de numérotation, donc on peut mettre +33 tout le temps.
Updated by Benjamin Dauvergne about 2 years ago
Je suis d'avis de ne rien faire de tout ça, d'accepter seulement ^0[67][0-9]{8}$
et l'équivalent pour la Belgique et d'avoir en dur une fonction pour convertir ça vers le numéro à appeler (et idem à l'enregistrement/la modification).
Updated by Paul Marillonnet about 2 years ago
Benjamin Dauvergne a écrit :
Je vais ajouter qu'il faut ajouter dans les settings les préfixes des DROM, qui font partie du https://fr.wikipedia.org/wiki/Plan_de_num%C3%A9rotation_en_France (bonne lecture).
Ça dit :
[...]
je pense que les numéros mobiles sont exposés sur les toutes les indicatifs nationaux du plan de numérotation, donc on peut mettre +33 tout le temps.
Hmm, à lire de la doc ici et là à ce sujet, il est dit que ça marche parce que les opérateurs savent “en général” reconstituer le code pays lorsqu’on tape un numéro à dix chiffres sans préfixe. Donc j’ai l’impression que justement non on ne peut pas mettre +33 tout le temps, l’intelligence est du côté opérateur qui retrouve le code. Quelqu’un a une compréhension différente de l’affaire ?
Est-ce qu’on est sûr que ça va marcher quand on a recours à un service tiers d’envoi de SMS ? Notamment est-ce que ces services acceptent systématiquement d’envoyer à numéros à dix chiffres sans mention du code pays ? Ou bien est-ce à nous de retrouver ce code avant l’appel au service d’envoi (auquel cas il faut aller dans le sens de ce que propose Agate) ?
Bref trop d’interrogations, avant de poursuivre je dois me renseigner là-dessus.
Updated by A. B. about 2 years ago
Paul Marillonnet a écrit :
Benjamin Dauvergne a écrit :
Je vais ajouter qu'il faut ajouter dans les settings les préfixes des DROM, qui font partie du https://fr.wikipedia.org/wiki/Plan_de_num%C3%A9rotation_en_France (bonne lecture).
Ça dit :
[...]
je pense que les numéros mobiles sont exposés sur les toutes les indicatifs nationaux du plan de numérotation, donc on peut mettre +33 tout le temps.Hmm, à lire de la doc ici et là à ce sujet, il est dit que ça marche parce que les opérateurs savent “en général” reconstituer le code pays lorsqu’on tape un numéro à dix chiffres sans préfixe. Donc j’ai l’impression que justement non on ne peut pas mettre +33 tout le temps, l’intelligence est du côté opérateur qui retrouve le code. Quelqu’un a une compréhension différente de l’affaire ?
Est-ce qu’on est sûr que ça va marcher quand on a recours à un service tiers d’envoi de SMS ? Notamment est-ce que ces services acceptent systématiquement d’envoyer à numéros à dix chiffres sans mention du code pays ? Ou bien est-ce à nous de retrouver ce code avant l’appel au service d’envoi (auquel cas il faut aller dans le sens de ce que propose Agate) ?
Bref trop d’interrogations, avant de poursuivre je dois me renseigner là-dessus.
Pour moi, si on doit s'interfacer avec des services / APIs tiers type Twilio ou SMS Factor, c'est quasiment sûr qu'il faudra un format unique et standard avec le prefixe (par exemple sms factor demande le prefixe 33 pour la france métropolitaine et si je me base sur https://www.smsfactor.com/tarifs-api-sms, il y a un pricing différent pour la Guyane ou la Réunion, et ça m'étonnerait fortement qu'ils fassent de la magie pour reconnaître quoi envoyer où si on ne fournit pas le bon indicateur pays).
Updated by Paul Marillonnet about 2 years ago
- Status changed from Solution proposée to En cours
Agate Berriot a écrit :
Pour moi, si on doit s'interfacer avec des services / APIs tiers type Twilio ou SMS Factor, c'est quasiment sûr qu'il faudra un format unique et standard avec le prefixe (par exemple sms factor demande le prefixe 33 pour la france métropolitaine et si je me base sur https://www.smsfactor.com/tarifs-api-sms, il y a un pricing différent pour la Guyane ou la Réunion, et ça m'étonnerait fortement qu'ils fassent de la magie pour reconnaître quoi envoyer où si on ne fournit pas le bon indicateur pays).
Oui c’est ma compréhension de l’affaire, je vais partir là-dessus.
J’ai poussé une branche qui reprend le premier patche mais avec l’usage d’un MultiValueField de Django, avec son MultiWidget qui va avec. Ça simplifie le code du formulaire et facilitera l’usage de phonenumbers. Je reprends ça demain.
Updated by Paul Marillonnet about 2 years ago
- File 0005-authentication-forms-add-user-phone-as-identifier-69.patch 0005-authentication-forms-add-user-phone-as-identifier-69.patch added
- File 0004-fields-add-a-PhoneField-69221.patch 0004-fields-add-a-PhoneField-69221.patch added
- File 0003-widgets-add-a-PhoneWidget-69221.patch 0003-widgets-add-a-PhoneWidget-69221.patch added
- File 0002-settings-add-supported-phone-country-codes-69221.patch 0002-settings-add-supported-phone-country-codes-69221.patch added
- File 0001-setup-add-phonenumbers-dependency-69221.patch 0001-setup-add-phonenumbers-dependency-69221.patch added
- Status changed from En cours to Solution proposée
Paul Marillonnet a écrit :
J’ai poussé une branche qui reprend le premier patche mais avec l’usage d’un MultiValueField de Django, avec son MultiWidget qui va avec. Ça simplifie le code du formulaire et facilitera l’usage de phonenumbers. Je reprends ça demain.
Voilà, ça simplifie les choses en effet, en particulier l’usage de phonenumbers, la possibilité de réutiliser cette class PhoneField(MultiValueField):
pour l’enregistrement du compte de l’usager, et le travail d’affichage du champ à l’usager (#69222).
Updated by Benjamin Dauvergne about 2 years ago
- Status changed from Solution proposée to En cours
- je ne suis pas pour l'ajout d'un PhoneField dans LoginForm, ça complexifie, il faut prendre n'importe quelle entrée qui ressemble à un numéro de téléphone, éventuellement la normaliser et chercher la desssus (comme on peut le faire en recherche libre sur les utilisateur).
- le PhoneField devrait sélectionner le pays par défaut
- le champ indicatif devrait rappeler le territoire avant l'indicatif "Guyane française (+xxx)", y a peut-être moyen d'extraire ça de libphonenumber d'aillerus
Updated by Benjamin Dauvergne about 2 years ago
On peut peut-être poussé tout ce qui est widget/field ici, et garder les aspects formulaire d'authent dans un autre ticket, pour avancer.
Updated by Paul Marillonnet about 2 years ago
Benjamin Dauvergne a écrit :
On peut peut-être poussé tout ce qui est widget/field ici, et garder les aspects formulaire d'authent dans un autre ticket, pour avancer.
Ok, je fais un autre ticket.
Updated by Paul Marillonnet about 2 years ago
- Related to Développement #70486: forms : avoir un champ et son widget pour l’authentification par numéro de téléphone added
Updated by Paul Marillonnet about 2 years ago
Benjamin Dauvergne a écrit :
- je ne suis pas pour l'ajout d'un PhoneField dans LoginForm, ça complexifie,
L’idée est de faire dans #69222 le travail en front de simplification, avoir un switch pour que l’un ou l’autre des champs email et téléphone s’affiche à l’usager dans la mire d’authentification, mais pas les deux à là fois.
- le PhoneField devrait sélectionner le pays par défaut
Ok.
- le champ indicatif devrait rappeler le territoire avant l'indicatif "Guyane française (+xxx)", y a peut-être moyen d'extraire ça de libphonenumber d'aillerus
Ok.
Updated by Paul Marillonnet about 2 years ago
- File 0001-authentication-forms-add-user-phone-as-identifier-69.patch 0001-authentication-forms-add-user-phone-as-identifier-69.patch added
- Status changed from En cours to Solution proposée
Paul Marillonnet a écrit :
- le PhoneField devrait sélectionner le pays par défaut
Ok.
Dans le champ PhoneField :
def __init__(self, **kwargs):
fields = (
CharField(max_length=8, initial=settings.DEFAULT_COUNTRY_CODE),
# […]
)
- le champ indicatif devrait rappeler le territoire avant l'indicatif "Guyane française (+xxx)", y a peut-être moyen d'extraire ça de libphonenumber d'aillerus
Ok.
Dans le widget associé, PhoneWidget :
prefixes = (
(code, '{area} (+{code})'.format(area=value['area'], code=code))
for code, value in settings.PHONE_COUNTRY_CODES.items()
)
et dans les settings :
PHONE_COUNTRY_CODES = {
'32': {'lang': 'BE', 'area': _('Belgium')},
'33': {'lang': 'FR', 'area': _('Metropolitan France')},
'262': {'lang': 'FR', 'area': _('Réunion')},
'508': {'lang': 'FR', 'area': _('Saint Pierre and Miquelon')},
'590': {'lang': 'FR', 'area': _('Guadeloupe')},
'594': {'lang': 'FR', 'area': _('French Guiana')},
'596': {'lang': 'FR', 'area': _('Martinique')},
}
Updated by Benjamin Dauvergne about 2 years ago
- Status changed from Solution proposée to Solution validée
Updated by Paul Marillonnet about 2 years ago
- Status changed from Solution validée to Résolu (à déployer)
commit f7d6895b94a102abdcace776366e4a41d9942559 Author: Paul Marillonnet <pmarillonnet@entrouvert.com> Date: Mon Sep 19 09:52:12 2022 +0200 authentication/forms: add user phone as identifier (#69221)
Updated by Paul Marillonnet almost 2 years ago
- Related to Développement #72430: authn : lorsqu’actif faire apparaître le champ téléphone au dessus du champ par mot de passe added
Updated by Paul Marillonnet almost 2 years ago
- Related to Développement #72440: authn mobile : XOR sur le username/email et le numéro de téléphone added
Updated by Paul Marillonnet almost 2 years ago
- Related to Développement #72449: authn mobile : conserver le PhoneField custom pour l’enregistrement uniquement, basculer sur un unique champ username/email/tél pour la page de connexion added
Updated by Transition automatique almost 2 years ago
- Status changed from Résolu (à déployer) to Solution déployée
authentication/forms: add user phone as identifier (#69221)