ZEP-17 : Elaboration de l'API des membres

a marqué ce sujet comme résolu.

Ah ok, je comprends mieux. J'ai donc complété le premier message avec les précisions sur l'OAuth2 apportées par firm1.

Quant au refresh token, je constate (toujours dans la documentation) que l'OAuth2 de la librairie Django fournit automatiquement cette possibilité. Par contre, il renvoi un access et un refresh token. Une idée du pourquoi, de la différence entre les deux ?

Tu t'authentifies, tu récupères un jeton d'accès.

A partir de ce moment là, tu peux faire des requêtes "au nom" de l'utilisateur qui s'est loggé.

Ce jeton va expirer au bout d'un moment. Lorsque tu vas prendre une 401 avec éventuellement comme complément d'information que ton token a expiré, tu vas utiliser le refreshToken ainsi que le client_secret pour te relogger sans repasser tous les credentials (login/mot de passe).

Plusieurs intérêts :

  • le token d'accès est le maillon faible, s'il est intercepté, tu peux prendre la place de l'utilisateur. En limitant sa durée de vie à une "session d'utilisation" (en gros inactivité pendant quelques minutes => expiration) voire en limitant sa durée de vie tout court à quelques minutes, tu limites le danger.

  • l'application n'a pas besoin de stocker le login et le mot de passe de l'utilisateur, et ne devrait pas le faire . Et c'est bien mieux comme ça pour tout le monde. (si jamais l'application est compromise, faille de sécurité, …)

  • si la réponse du serveur contenant l'accessToken et le refreshToken est interceptée, l'accessToken va pouvoir être utilisé (mais c'est limité dans le temps… même si c'est extrêmement dangereux) par contre pour le refreshToken il faut le client_secret. Qui n'est pas dans la réponse du serveur.

  • permet également à un client, n'importe où, n'importe quand d'invalider des accessToken, sans avoir besoin de saisir à nouveau ses login / mot de passe sur tous ses appareils. En gros, je dis "oulà, y'a une activité suspecte sur mon compte, un de mes accessToken a été intercepté, invalide les tous"

C'est comme ça que je comprends la chose.

+0 -0

Je constate que j'avais une connaissance basique du fonctionnement des tokens (s'authentifier, recevoir un token et l'utiliser dans les requêtes pour parler "au nom de"). Donc, si nous prenons un exemple de réponse de Django-Rest :

1
2
3
4
5
6
{
  "access_token": "<your-access-token>", 
  "scope": "read", 
  "expires_in": 86399, 
  "refresh_token": "<your-refresh-token>"
}
  1. L'utilisateur se log pour la première fois grâce à un client à l'API
  2. Le serveur lui renvoi son access token avec son expiration et son refresh token sans expiration
  3. Durant la session, l'access token est utilisé dans les requêtes
  4. A chaque fois que l'access token expire, le client refait une authentification avec le refresh token et la clé secrète

Et ce système pour des problèmes de sécurité dont certains que tu as cité.

Tout bon ?

C'est comme cela que je l'ai compris oui.

Maintenant, vu que c'est moi qui t'ai aiguillé là-dessus et que franchement OAuth2 (la spec officielle) je l'ai jamais mise en application moi-même, attends ptêtre un retour de firm1 ou artragis pour te le confirmer.

+0 -0

Je suis d'accord pour avoir d'autres avis mais de toute façon, c'est un peu le mécanisme qui ressort de la documentation. Cela ne devrait pas poser problème. Je fais une nouvelle révision du premier message après un troisième avis s'il est dans notre sens.

Sinon, débattons sur la sauvegarde de l'ETag ou nous pouvons estimer que notre spec est assez précise pour passer en validation ?

Bon, j'ai repris ma lecture, encore quelques remarques.

ainsi qu'un message d'erreur compréhensible par le développeur de l'API.

ZEP-17

"ainsi qu'un message d'erreur compréhensible par le développeur du client de l'API."

Seul le JSON est accepté.

ZEP-17

Y'a t-il une vraie raison au fait qu'on interdise les autres format ? Je peux comprendre qu'on se dise qu'il faut au minimum du json, mais dire qu'il ne faudrait QUE ça c'est peut-être pour des raisons particulière. J'aimerai donc les connaître si possible.

Même réflexion pour le format de sortie.

"is_staff": true,

ZEP-17

Le champ is_staff qui fait partie inhérante du modèle de donnée de Django n'est aujourd'hui pas utilisé dans ZdS, donc ça ne sert à rien de le renvoyer. Il est plus pertinent ici de renvoyer l'ensemble des groupes (sous forme de array) dont fait parti le membre (voir la doc pour plus d'information).

Exemple d'objet […]

ZEP-17

On a aucune précision sur le format de rendu des informations. On a plusieurs solution ici :

  1. On ne renvoi que les textes au format markdown : dans ce cas précis, les clients de l'api de type html doivent se taper le parsing zmd -> html
  2. On ne renvoi que les textes au format html : on consomme beaucoup trop de reseau à chaque fois, et on a pas la source markdown.
  3. On renvoi les deux formats systématiquement : encore beaucoup trop de bande passante consommée inutilement.
  4. On renvoi le format html sans les balises htmls. Par exemple si la signature en html donne <p>Cliquez <a href="perdu.com">ici</a></p> on renverrait Cliquez ici : le problème là c'est que du coup les liens n'auront plus de sens
  5. On renvoi uniquement le format demandé (en précisant la nature du format dans les entêtes http) : perso, c'est la solution que je pense être la meilleure

Je m'arrête ici pour ma lecture.

Renvoyer le html sera nécessaire. Renvoyer le markdown, et encore pire, l'utiliser coté client pour faire un rendu, est une mauvaise idée. Au delà du fait que faire un parseur coté client == re-dev toutes nos extensions, cela va poser des problèmes car chaque parseurs à un comportement différents sur certains cas qui ne sont pas si anodins que ça. Du coup c'est la porte ouverte à des bugs type "Avec ce markdown j'ai le bon rendu sur le client mais pas sur le site" (ou l'inverse)… Bref ça annonce des bugs sans nom !

http://zestedesavoir.com/forums/sujet/622/zep-02-elaboration-dune-api/?page=3#p8936

au niveau des formats de sortie, sauf si vraiment c'est complètement transparent côté serveur, autant ne pas s'emmerder et renvoyer du JSON (c'est ce que fait Twitter par exemple). Si jamais plusieurs formats sont acceptés en entrée et en sortie, penser à se baser sur les headers HTTP Content-Type et Accept envoyés par le client.

Je n'ai pas proposé plus que ça parce que je ne connais pas Django, je ne sais pas de quel type de marshaller vous disposez, etc.

Typiquement, avec Grails, on se cantonnerait à render membre as JSON ou render membre as XML en fonction du header Accept envoyé. Et même dans ce cas, je ne sais pas si pour une API que je crée aujourd'hui from scratch je renverrai de l'XML, très honnêtement.

+1 -0

Je n'ai pas proposé plus que ça parce que je ne connais pas Django, je ne sais pas de quel type de marshaller vous disposez, etc.

Typiquement, avec Grails, on se cantonnerait à render membre as JSON ou render membre as XML en fonction du header Accept envoyé. Et même dans ce cas, je ne sais pas si pour une API que je crée aujourd'hui from scratch je renverrai de l'XML, très honnêtement.

Javier

Je ne sais pas ce qui est dispo dans Django ou dans le framework qui va etre utilisé pour l'API mais clairement en Python, même si faut le refaire, c'est ridiculement rapide a faire ce genre de conversion.

A vous de voir.

Y'a des mécanismes assez élégants dans les frameworks Java EE et dérivés pour faire ça via intercepteurs et annotations.

En gros sur toute méthode API on peut avoir un intercepteur qui étudie les headers de la requête et instancie le bon converter/marshaller pour l'injecter ensuite dans la méthode. Du coup quand on lit (ou écrit) le code de la méthode, on ne se préoccupe de rien, on renvoie juste l'objet (ici un membre, ou une liste de membres).

J'imagine qu'avec les décorateurs Python on peut faire ce genre de choses.

Mon propos était plus que toutes les APIs que j'ai étudiées dernièrement ont plus ou moins droppé le support de l'XML. J'ai cité Twitter dans l'autre topic, Github n'accepte plus que le JSON en entrée depuis leur API v3 aussi.

Mais si vous pensez que proposer d'envoyer/recevoir des données formatées en XML en plus du JSON a un vrai intérêt pour certains clients alors pourquoi pas. M'enfin ça me semblait pas franchement indispensable.

+0 -0

Je suis bien d'accord avec toi Javier que le xml n'est peut être pas pertinent comme format en 2014, mais c'est le fait que dans la ZEP on interdise clairement les autres formats possibles qui m'a un peu interpelé. IL n'y a pas que le xml et le json. On peut aussi demander en entrée du yaml par exemple.

Bref, pour moi dans la ZEP on devrait laisser la liberté sur les formats d'entrée/sortie en demandant au minimum le json. Si le dev peut en faire plus (et que ce n'est pas buggué) ça sera un bonus.

Renvoyer le html sera nécessaire. Renvoyer le markdown, et encore pire, l'utiliser coté client pour faire un rendu, est une mauvaise idée. Au delà du fait que faire un parseur coté client == re-dev toutes nos extensions, cela va poser des problèmes car chaque parseurs à un comportement différents sur certains cas qui ne sont pas si anodins que ça. Du coup c'est la porte ouverte à des bugs type "Avec ce markdown j'ai le bon rendu sur le client mais pas sur le site" (ou l'inverse)… Bref ça annonce des bugs sans nom !

Kje

Pour le format de rendu, le problème qu'on peut avoir en ne renvoyant que le html c'est que les client de l'API de type mobile par exemple, sont obligé d'inclure des vieilles briques juste pour interpréter correctement le html. Après oui, renvoyer du markdown c'est la porte d'entrée à plein de problème. C'est bien pour ça que je préfère laisser le choix au client de l'API de choisir son format de retour (via l'entête http) avec peut être par defaut un retour de type html.

OK, si tu veux éviter de fermer des portes ça ne me dérange pas. Si le dev en a le temps et que ça lui fait plaisir pourquoi pas. Je pensais qu'il était important de cadrer le dev et de faire simple dans un premier temps. Maintenant, ça ne me pose aucun pb.

Par contre pour ta dernière remarque : quel en-tête http ?

Tu veux concaténer ça au Accept? :\ Ou en utiliser un "maison" (X-Data-Format ou truc du style) ?

+0 -0

J'ai fais une nouvelle révision (3) en apportant les modifications suivantes :

  • Ajout du fonctionnement de l'access et refresh token dans la section de l'authentification ;
  • Demande le support du JSON dans les formats d'entrés et de sorties à minima, le reste étant du bonus ;
  • Retrait de l'information is_staff dans la représentation JSON d'un membre.

Concernant la dernière problématique relevé par firm1, je ne comprends pas pourquoi nous en débattons ici. Il va falloir en débattre quand nous rédigerons les spécs des autres modules mais cela ne me semble pas nécessaire pour le module des membres où toutes les informations sont en bases et sans markdown (limite la signature mais c'est minime).

Est-ce donc vraiment le lieu et le moment d'en débattre ?

Concernant la dernière problématique relevé par firm1, je ne comprends pas pourquoi nous en débattons ici. Il va falloir en débattre quand nous rédigerons les spécs des autres modules mais cela ne me semble pas nécessaire pour le module des membres où toutes les informations sont en bases et sans markdown (limite la signature mais c'est minime).

Andr0

Comme le dit mon VDD, il y'a la biographie, ainsi que la signature qui ne peuvent pas être interprété decemment si on donne du markdown. Donc pour moi, il faut en discutter quelque part pour pouvoir valider cette ZEP.

Tu veux concaténer ça au Accept? :\ Ou en utiliser un "maison" (X-Data-Format ou truc du style) ?

Javier

Je partirai plutôt sur une adaptation une entête maison. Pour le nom, je n'y ai pas encore réfléchi, mais il faudrait browser un peu ce qui se fait ailleurs (je n'ai pas trop le temps pour ça en ce moment).

Encore une fois, on en avait discuté dans l'autre topic, s'il s'avérait que certaines informations ne devaient pas apparaître dans le modèle renvoyé au client, cette étape était incorporée dès la v0.

Javier

Du coup a quoi sert donc la version 0.2 présentée dans la ZEP ?

Manifestement elle ne devrait plus être là.

Maintenant est-ce-que c'est vraiment un point de blocage majeur pour la spec' ?

Les versions sont données à titre indicatif pour pouvoir avancer petit à petit, une problématique technique à la fois. Y'a beaucoup, beaucoup plus important dans la spec que ce point de détail (Oauth ? ETag ?)

+0 -0

Je mets à jour ce soir le premier message pour retirer is_staff du tableau représentant un member et pour retirer la v0.2 qui ne sert, effectivement, plus à rien. J'ai commencé un petit truc rapide en local et, dans les faits, le Serializer apparait directement.

En ce qui concerne OAuth, je pense que nous sommes bon et pour l'ETag, il faut encore définir comment sauvegarder cette donnée.

Maintenant est-ce-que c'est vraiment un point de blocage majeur pour la spec' ?

Javier

Je régis au fur et a mesure de ma lecture.

Y'a beaucoup, beaucoup plus important dans la spec que ce point de détail (Oauth ? ETag ?)

Javier

J'ai déjà donné mes remarques sur le point OAuth, et il me semble que ça a été décidé qu'on est bon pour l'OAuth2.

pour l'ETag, il faut encore définir comment sauvegarder cette donnée.

Andr0

L'ETag n'a pas besoin d'être sauvegardé, car il est tout simplement calculé.

D'ailleurs il existe un paquet d'extensions à djangorestframework qu'on va certainement utiliser pour travailler sur ces aspects de cache et etag. C'est intégré presque naturellement dans la lib (cache, la pagination, etc.).

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte