From c22dfe89fd2129319b901e85e3cb41d8b06a6ef7 Mon Sep 17 00:00:00 2001 From: Fred Pauchet Date: Thu, 12 May 2016 11:46:52 +0200 Subject: [PATCH 1/5] add reverse_url func --- source/mvc/urls.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/mvc/urls.rst b/source/mvc/urls.rst index 94a883d..5bc8779 100644 --- a/source/mvc/urls.rst +++ b/source/mvc/urls.rst @@ -43,4 +43,12 @@ De cette manière, dans nos templates, on peut à présent construire un lien ve .. code-block:: html - {{ yearvar }} Archive \ No newline at end of file + {{ yearvar }} Archive + +De la même manière, on peut également récupérer l'URL de destination pour n'importe quel libellé, de la manière suivante: + +.. code-block:: python + + from django.core.urlresolvers import reverse_lazy + + wishlists_url = reverse_lazy('wishlists') \ No newline at end of file From 8bb5ec1730284c394553c6c854527b83c3e10ab4 Mon Sep 17 00:00:00 2001 From: jaguarondi Date: Sun, 15 May 2016 21:26:57 +0200 Subject: [PATCH 2/5] Update production --- source/production/admin_with_static.png | Bin 0 -> 6515 bytes source/production/environment.rst | 33 +++++++++- source/production/gunicorn.rst | 82 ++++++++++++++++++++++++ source/production/monitoring.rst | 55 +++++++++++++--- source/production/nginx.rst | 47 ++++++++++++-- 5 files changed, 202 insertions(+), 15 deletions(-) create mode 100644 source/production/admin_with_static.png diff --git a/source/production/admin_with_static.png b/source/production/admin_with_static.png new file mode 100644 index 0000000000000000000000000000000000000000..66af9167e49c46d5f85cfe5c30dc75cfa5cd9e93 GIT binary patch literal 6515 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 literal 0 HcmV?d00001 diff --git a/source/production/environment.rst b/source/production/environment.rst index 8fb9ad3..6c87f92 100644 --- a/source/production/environment.rst +++ b/source/production/environment.rst @@ -74,7 +74,7 @@ Il ne nous reste plus qu'à mettre à jour la DB. On commance par créer le fich (gwift)gwift@gwift:~$ touch gwift/gwift/settings/local.py -Et le contenu de local.py, avec la clé secrète et les paramètres pour se connecter à la DB: +Et le contenu de local.py, avec la clé secrète, les paramètres pour se connecter à la DB et l'endroit où mettre les fichiers statics (voir point suivant): .. code-block:: python @@ -88,6 +88,12 @@ Et le contenu de local.py, avec la clé secrète et les paramètres pour se conn # Allowed host needed to be defined in production ALLOWED_HOSTS = ["sever_name.com", "www.sever_name.com"] + + # Be sure to force https for csrf cookie + CSRF_COOKIE_SECURE = True + + # Same for session cookie + SESSION_COOKIE_SECURE = True # DB DATABASES = { @@ -100,6 +106,13 @@ Et le contenu de local.py, avec la clé secrète et les paramètres pour se conn 'PORT': '', # Set to empty string for default. } } + + # Add static root + STATIC_ROOT = "/webapps/gwift/gwift/static" + + STATICFILES_DIRS = [ + os.path.join(BASE_DIR, "static"), + ] Finalement, on peut mettre à jour la DB et créer un super utilisateur: @@ -108,6 +121,24 @@ Finalement, on peut mettre à jour la DB et créer un super utilisateur: (gwift)gwift@gwift:~$ python manage.py migrate (gwift)gwift@gwift:~$ python manage.py createsuperuser +Fichiers statics +================ + +Django n'est pas fait pour servir les fichiers statics. Tous les fichiers statics doivent donc être déplacés dans un répertoire pour que Nginx puisse les servir facilement. + +On commence par créer le répertoire où mettre les fichiers statics comme configuré dans le fichier local.py: + +.. code-block:: shell + + (gwift)gwift@gwift:~$ mkdir /webapps/gwift/gwift/static + +Et on utilise django pour copier tous les fichiers statics au bon endroit: + +.. code-block:: shell + + (gwift)gwift@gwift:~$ python manage.py collectstatic + + Test ==== diff --git a/source/production/gunicorn.rst b/source/production/gunicorn.rst index e69de29..beef77a 100644 --- a/source/production/gunicorn.rst +++ b/source/production/gunicorn.rst @@ -0,0 +1,82 @@ +************* +Gunicorn +************* + +Nous allons utiliser ``gunicorn`` comme serveur d'applications, le serveur fourni par django n'étant pas fait pour être utilisé en production. + +Gunicorn a déjà été installé lors de la préparation de l'environnement. De même que ``setproctitle``, qui est nécessaire pour donner le nom de l'application aux processus python lancés par gunicorn. + +Nous pouvons donc directement tester s'il fonctionne: + +.. code-block:: shell + + (gwift)gwift@gwift:~$ gunicorn gwift.wsgi:application --bind esever_name.com:8000 + +Et en se rendant sur server_name.com:8000/admin, on obtient la même chose qu'avec le serveur de django: + +.. image:: production/admin_without_static.png + :align: center + +Nous allons maintenant créer un ficheir qui se chargera de lancer gunicorn correctement, que l'on sauve dans ``/webapps/gwift/gwift/bin/gunicorn_start``: + +.. code-block:: shell + + #!/bin/bash + + # Define settings for gunicorn + NAME="gwift" # Name of the application + DJANGODIR=/webapps/gwift/gwift/gwift # Django project directory + SOCKFILE=/webapps/gwift/gwift/run/gunicorn.sock # we will communicte using this unix socket + USER=gwift # the user to run as + GROUP=webapps # the group to run as + NUM_WORKERS=3 # how many worker processes should Gunicorn spawn + DJANGO_SETTINGS_MODULE=gwift.settings # which settings file should Django use + DJANGO_WSGI_MODULE=gwift.wsgi # WSGI module name + + echo "Starting $NAME as `whoami`" + + # Activate the virtual environment + source /webapps/gwift/.virtualenvs/gwift/bin/activate + cd $DJANGODIR + export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE + export PYTHONPATH=$DJANGODIR:$PYTHONPATH + + # Create the run directory if it doesn't exist + RUNDIR=$(dirname $SOCKFILE) + test -d $RUNDIR || mkdir -p $RUNDIR + + # Start your Django Unicorn + # Programs meant to be run under supervisor should not daemonize themselves (do not use --daemon) + exec gunicorn ${DJANGO_WSGI_MODULE}:application \ + --name $NAME \ + --workers $NUM_WORKERS \ + --user=$USER --group=$GROUP \ + --bind=unix:$SOCKFILE \ + --log-level=debug \ + --log-file=- + +Explications: + + * NUM_WORKERS : gunicorn lance autant de worker que ce nombre. Un worker représente l'équivallant d'une instance de django et ne peut traiter qu'une requête à la fois. Traditionnellement, on créé autant de worker que le double du nombre de processeurs plus un. + * SOCKFILE : on configure gunicorn pour communiquer via un socket unix, ce qui est plus efficace de le faire par tcp/ip + +Le script se charge donc de définir les options de configuration de gunicorn, de lancer l'environnement virtuel et ensuite gunicorn. + +On peut le tester avec la commande suivante (hors environnement virtuel): + +.. code-block:: shell + + gwift@gwift:~$ source /webapps/gwift/gwift/bin/gunicorn_start + +Et avec un petit ``ps`` dans un autre shell: + +.. code-block:: shell + + gwift@gwift:~$ ps -u gwift -F + UID PID PPID C SZ RSS PSR STIME TTY TIME CMD + gwift 31983 15685 0 18319 15084 1 Apr29 ? 00:00:01 gunicorn: master [gwift] + gwift 31992 31983 0 35636 29312 1 Apr29 ? 00:00:00 gunicorn: worker [gwift] + gwift 31993 31983 0 35634 29280 2 Apr29 ? 00:00:00 gunicorn: worker [gwift] + gwift 31994 31983 0 35618 29228 0 Apr29 ? 00:00:00 gunicorn: worker [gwift] + +On voit donc bien qu'il y a un maître et trois workers. \ No newline at end of file diff --git a/source/production/monitoring.rst b/source/production/monitoring.rst index 360e5ba..eefd651 100644 --- a/source/production/monitoring.rst +++ b/source/production/monitoring.rst @@ -2,15 +2,50 @@ Monitoring ********** +Pour lancer et surveiller gunicorn, nous allons utiliser supervisord, qui est un démon sous lunix permettant de lancer d'autre programmes. + +On commence par l'installer: + .. code-block:: shell - [program:simple] - command={{ virtualenv_path }}/bin/gunicorn simple.app:app -w {{ workers }} --log-file={{ appdir }}/logs/gunicorn.log --bind 127.0.0.1:{{ proxy_port }} - directory={{ appdir }}/ - environment=PATH="{{ virtualenv_path }}/bin" - user=nobody - autostart=true - autorestart=true - killasgroup = true - redirect_stdout=true - redirect_stderr=true \ No newline at end of file + $$$ aptitude install supervisor + +On crée ensuite une fichier de configuration, ``/etc/supervisor/conf.d/gwift.conf``, qui sera lu au démarage de supervisord. + +.. code-block:: shell + + [program:gwift] + command = /webapps/gwift/gwift/bin/gunicorn_start ; Command to start + user = gwift ; User to run as + stdout_logfile = /webapps/gwift/gwift/logs/gunicorn_supervisor.log ; Where to write log messages + environment=LANG=en_US.UTF-8,LC_ALL=en_US.UTF-8 ; Set UTF-8 as default encoding + autostart=true ; Start the program when supervisord is starting + autorestart=unexpected ; Restart program if it exited anormaly + redirect_stdout=true ; Redirect program output to the log file + redirect_stderr=true ; Redirect program error to the log file + +On peut alors démarer supervisor: + + +.. code-block:: shell + + $$$ service supervisor start + +On peut vérifier que notre site est bien en train de tourner, à l'aide de la commande ``supervisorctl``: + +.. code-block:: shell + + $$$ supervisorctl status gwift + gwift RUNNING pid 31983, uptime 0:01:00 + +Pour gérer le démarage ou l'arrêt de notre application, nous pouvons effectuer les commandes suivantes: + +.. code-block:: shell + + $$$ supervisorctl stop gwift + gwift: stopped + root@ks3353535:/etc/supervisor/conf.d# supervisorctl start gwift + gwift: started + root@ks3353535:/etc/supervisor/conf.d# supervisorctl restart gwift + gwift: stopped + gwift: started diff --git a/source/production/nginx.rst b/source/production/nginx.rst index 5d317b5..f8cf293 100644 --- a/source/production/nginx.rst +++ b/source/production/nginx.rst @@ -7,6 +7,12 @@ FrontEnd Nginx est là pour agir en tant que front-end Web. A moins d'avoir configuré un mécanisme de cache type `Varnish `_, c'est lui qui va recevoir la requête envoyée par l'utilisateur, gérer les fichiers et les informations statiques, et transmettre toute la partie dynamique vers Gunicorn. +Pour l'installer, on effectue la commande suivante: + +.. code-block:: shell + + $$$ aptitude install nginx + L'exemple ci-dessous se compose de plusieurs grandes parties: commune (par défaut), static, uploads, racine. Partie commune @@ -18,7 +24,7 @@ Partie commune * keepalive ?? * La compression Gzip doit-elle être activée ? * Avec quels paramètres ? [gzip_comp_level 7, gzip_proxied any] - * Quels types de fichiers GZip doit-il prendre en compte ? [ + * Quels types de fichiers GZip doit-il prendre en compte ? * Où les fichiers de logs doivent-ils être stockés ? [/logs/access.log & /logs/error.log] Fichiers statiques @@ -36,13 +42,33 @@ Si vous souhaitez implémenter un mécanisme d'accès géré, supprimez cette pa Racine ------ -La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn. En gros, et comme déjà expliqué, Gunicorn tourne en local sur un port (eg. 8001); la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le port 8001. Ceci est complétement transparent pour l'utilisateur de notre application. +La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn via un socket unix. En gros, et comme déjà expliqué, Gunicorn tourne en local sur un port (eg. 8001); la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le port 8001. Ceci est complétement transparent pour l'utilisateur de notre application. + +On délare un upstream pour préciser à nginx comment envoyer les requêtes à gunicorn: + +.. code-block:: shell + + upstream gwift_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response (in case the Unicorn master nukes a + # single worker for timing out). + + server unix:/directory/to/gunicorn.sock fail_timeout=0; + } Au final -------- .. code-block:: shell + upstream gwift_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response (in case the Unicorn master nukes a + # single worker for timing out). + + server unix:/directory/to/gunicorn.sock fail_timeout=0; + } + server { listen 80; client_max_body_size 4G; @@ -58,7 +84,7 @@ Au final error_log {{ cwd }}/logs/error.log; location /static/ { - alias {{ static_root }}/; + alias /webapps/gwift/gwift/static; gzip on; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js; gzip_comp_level 9; @@ -80,10 +106,23 @@ Au final proxy_set_header Host $http_host; proxy_redirect off; - proxy_pass http://127.0.0.1:{{ proxy_port }}; + proxy_pass http://gwift_server; } } +Dans notre cas, et à adbater suivant les besoins, nous avans créé le fichier ``/etc/nginx/sites-available/gwift`` et créé un lien symbolique dans ``/etc/nginx/sites-enabled/gwift`` pour l'activer. Ensuite, nous pouvons redémarer nginx: + +.. code-block:: shell + + $$$ service nginx restart + +Et maintenant, si on se connecte à notre server sur www.sever_name.com/admin, nous obtenons le site suivant: + +.. image:: production/admin_with_static.png + :align: center + +Où l'on peut voir que la mise en forme est correcte, ce qui signifie que les fichiers statics sont bien servis par nginx. + Modules complémentaires ======================= From 7d95f37c36b968eb593c4ffaf08de3825a1a9cbf Mon Sep 17 00:00:00 2001 From: jaguarondi Date: Sun, 15 May 2016 21:37:32 +0200 Subject: [PATCH 3/5] misspelling --- source/production/gunicorn.rst | 2 +- source/production/monitoring.rst | 3 +-- source/production/nginx.rst | 8 ++++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/source/production/gunicorn.rst b/source/production/gunicorn.rst index beef77a..9e39fb5 100644 --- a/source/production/gunicorn.rst +++ b/source/production/gunicorn.rst @@ -17,7 +17,7 @@ Et en se rendant sur server_name.com:8000/admin, on obtient la même chose qu'av .. image:: production/admin_without_static.png :align: center -Nous allons maintenant créer un ficheir qui se chargera de lancer gunicorn correctement, que l'on sauve dans ``/webapps/gwift/gwift/bin/gunicorn_start``: +Nous allons maintenant créer un fichier qui se chargera de lancer gunicorn correctement, que l'on sauve dans ``/webapps/gwift/gwift/bin/gunicorn_start``: .. code-block:: shell diff --git a/source/production/monitoring.rst b/source/production/monitoring.rst index eefd651..15ec9d6 100644 --- a/source/production/monitoring.rst +++ b/source/production/monitoring.rst @@ -24,8 +24,7 @@ On crée ensuite une fichier de configuration, ``/etc/supervisor/conf.d/gwift.co redirect_stdout=true ; Redirect program output to the log file redirect_stderr=true ; Redirect program error to the log file -On peut alors démarer supervisor: - +On peut alors démarer supervisord: .. code-block:: shell diff --git a/source/production/nginx.rst b/source/production/nginx.rst index f8cf293..6d37a45 100644 --- a/source/production/nginx.rst +++ b/source/production/nginx.rst @@ -42,7 +42,7 @@ Si vous souhaitez implémenter un mécanisme d'accès géré, supprimez cette pa Racine ------ -La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn via un socket unix. En gros, et comme déjà expliqué, Gunicorn tourne en local sur un port (eg. 8001); la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le port 8001. Ceci est complétement transparent pour l'utilisateur de notre application. +La partie racine de votre domaine ou sous-domaine fera simplement le *pass_through* vers l'instance Gunicorn via un socket unix. En gros, et comme déjà expliqué, Gunicorn tourne en local et écoute un socket; la requête qui arrive sur le port 80 ou 443 est prise en compte par NGinx, puis transmise à Gunicorn sur le socket. Ceci est complétement transparent pour l'utilisateur de notre application. On délare un upstream pour préciser à nginx comment envoyer les requêtes à gunicorn: @@ -72,7 +72,7 @@ Au final server { listen 80; client_max_body_size 4G; - server_name {{ domain_name }}; + server_name sever_name.com www.sever_name.com; keepalive_timeout 5; gzip on; @@ -110,13 +110,13 @@ Au final } } -Dans notre cas, et à adbater suivant les besoins, nous avans créé le fichier ``/etc/nginx/sites-available/gwift`` et créé un lien symbolique dans ``/etc/nginx/sites-enabled/gwift`` pour l'activer. Ensuite, nous pouvons redémarer nginx: +Dans notre cas, et à adapter suivant les besoins, nous avons créé le fichier ``/etc/nginx/sites-available/gwift``, ainsi qu'un lien symbolique dans ``/etc/nginx/sites-enabled/gwift`` pour l'activer. Ensuite, nous pouvons redémarer nginx: .. code-block:: shell $$$ service nginx restart -Et maintenant, si on se connecte à notre server sur www.sever_name.com/admin, nous obtenons le site suivant: +Si on se connecte à notre server sur www.sever_name.com/admin, nous obtenons le site suivant: .. image:: production/admin_with_static.png :align: center From e15041342c0bc107cd5743d93f8ec4cb967a2244 Mon Sep 17 00:00:00 2001 From: Fred Date: Sun, 15 May 2016 22:36:13 +0200 Subject: [PATCH 4/5] add a little bit of auth --- source/auth.rst | 44 ++++++++++++++++++++++++++++++++++++++++++++ source/index.rst | 1 + 2 files changed, 45 insertions(+) create mode 100644 source/auth.rst diff --git a/source/auth.rst b/source/auth.rst new file mode 100644 index 0000000..3c65089 --- /dev/null +++ b/source/auth.rst @@ -0,0 +1,44 @@ +**************** +Authentification +**************** + +Comme on l'a vu dans la partie sur le modèle, nous souhaitons que le créateur d'une liste puisse retrouver facilement les éléments qu'il aura créé. Ce dont nous n'avons pas parlé cependant, c'est la manière dont l'utilisateur va pouvoir créer son compte et s'authentifier. La `document `_ est très complète, nous allons essayer de la simplifier au maximum. Accrochez-vous, le sujet peut être complexe. + +On peut résumer le mécanisme d'authentification de la manière suivante: + + * Si vous voulez modifier les informations liées à un utilisateur, orientez-vous vers la modification du modèle. Comme nous le verrons ci-dessous, il existe trois manières de prendre ces modifications en compte. + * Si vous souhaitez modifier la manière dont l'utilisateur se connecte, alors vous devrez modifier le *backend*. + +Modification du modèle +====================== + +Dans un premier temps, Django a besoin de manipuler `des instances de type `_ ``django.contrib.auth.User``. Cette classe implémente les champs suivants: + + * ``username`` + * ``first_name`` + * ``last_name`` + * ``email`` + * ``password`` + * ``date_joined``. + +D'autres champs, comme les groupes auxquels l'utilisateur est associé, ses permissions, savoir s'il est un super-utilisateur, ... sont moins pertinents pour le moment. Avec les quelques champs déjà définis ci-dessus, nous avons de quoi identifier correctement nos utilisateurs. Inutile d'implémenter nos propres classes, puisqu'elles existent déjà :-) + +Si vous souhaitez ajouter un champ, il existe trois manières de faire. + +Extension du modèle existant +---------------------------- + +Le plus simple consiste à créer une nouvelle classe, et à faire un lien de type ``OneToOne`` vers la classe ``django.contrib.auth.User``. De cette manière, on ne modifie rien à la manière dont Django authentife ses utlisateurs: tout ce qu'on fait, c'est un lien vers une table nouvellement créée, comme on l'a déjà vu au point [...voir l'héritage de modèle]. L'avantage de cette méthode, c'est qu'elle est extrêmement flexible, et qu'on garde les mécanismes Django standard. Le désavantage, c'est que pour avoir toutes les informations de notre utilisateur, on sera obligé d'effectuer une jointure sur le base de données, ce qui pourrait avoir des conséquences sur les performances. + +Substitution +------------ + +Avant de commencer, sachez que cette étape doit être effectuée **avant la première migration**. Le plus simple sera de définir une nouvelle classe héritant de ``django.contrib.auth.User`` et de spécifier la classe à utiliser dans votre fichier de paramètres. Si ce paramètre est modifié après que la première migration ait été effectuée, il ne sera pas pris en compte. Tenez-en compte au moment de modéliser votre application. + +.. code-block:: python + + AUTH_USER_MODEL = 'myapp.MyUser' + +Notez bien qu'**il ne faut pas** spécifier le package ``.models`` dans cette injection de dépendances. + +Ce qui n'existe pas par contre, ce sont les vues. Django propose donc tout le mécanisme de gestion des utilisateurs, excepté le visuel (hors administration). \ No newline at end of file diff --git a/source/index.rst b/source/index.rst index 7505ead..29de2a3 100644 --- a/source/index.rst +++ b/source/index.rst @@ -17,6 +17,7 @@ Contents: models mvc forms + auth admin docs integration From 9f3b6064d43af0651e484330e38d31d92b161e24 Mon Sep 17 00:00:00 2001 From: Fred Date: Sun, 15 May 2016 22:56:16 +0200 Subject: [PATCH 5/5] oauth --- source/auth.rst | 51 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/source/auth.rst b/source/auth.rst index 3c65089..52ae8e0 100644 --- a/source/auth.rst +++ b/source/auth.rst @@ -1,12 +1,16 @@ -**************** +================ Authentification -**************** +================ Comme on l'a vu dans la partie sur le modèle, nous souhaitons que le créateur d'une liste puisse retrouver facilement les éléments qu'il aura créé. Ce dont nous n'avons pas parlé cependant, c'est la manière dont l'utilisateur va pouvoir créer son compte et s'authentifier. La `document `_ est très complète, nous allons essayer de la simplifier au maximum. Accrochez-vous, le sujet peut être complexe. +**************************** +Mécanisme d'authentification +**************************** + On peut résumer le mécanisme d'authentification de la manière suivante: - * Si vous voulez modifier les informations liées à un utilisateur, orientez-vous vers la modification du modèle. Comme nous le verrons ci-dessous, il existe trois manières de prendre ces modifications en compte. + * Si vous voulez modifier les informations liées à un utilisateur, orientez-vous vers la modification du modèle. Comme nous le verrons ci-dessous, il existe trois manières de prendre ces modifications en compte. Voir également `ici `_. * Si vous souhaitez modifier la manière dont l'utilisateur se connecte, alors vous devrez modifier le *backend*. Modification du modèle @@ -39,6 +43,43 @@ Avant de commencer, sachez que cette étape doit être effectuée **avant la pre AUTH_USER_MODEL = 'myapp.MyUser' -Notez bien qu'**il ne faut pas** spécifier le package ``.models`` dans cette injection de dépendances. +Notez bien qu'**il ne faut pas** spécifier le package ``.models`` dans cette injection de dépendances: le schéma à indiquer est bien ``.``. -Ce qui n'existe pas par contre, ce sont les vues. Django propose donc tout le mécanisme de gestion des utilisateurs, excepté le visuel (hors administration). \ No newline at end of file +Backend +======= + +[blabla...] + + +********* +Templates +********* + +Ce qui n'existe pas par contre, ce sont les vues. Django propose donc tout le mécanisme de gestion des utilisateurs, excepté le visuel (hors administration). En premier lieu, ces paramètres sont fixés dans le fichier `settings `_. On y trouve par exemple les paramètres suivants: + + * ``LOGIN_REDIRECT_URL``: si vous ne spécifiez pas le paramètre ``next``, l'utilisateur sera automatiquement redirigé vers cette page. + * ``LOGIN_URL``: l'URL de connexion à utiliser. Par défaut, l'utilisateur doit se rendre sur la page ``/accounts/login``. + + +*********************** +Social-Authentification +*********************** + +Voir ici : `python social auth `_ + +Un petit mot sur OAuth +---------------------- + +OAuth +===== + +OAuth est un standard libre définissant un ensemble de méthodes à implémenter pour l'accès (l'autorisation) à une API. Son fonctionnement se base sur un système de jetons (Tokens), attribués par le possesseur de la ressource à laquelle un utilisateur souhaite accéder. + +Le client initie la connexion en demandant un jeton au serveur. Ce jeton est ensuite utilisée tout au long de la connexion, pour accéder aux différentes ressources offertes par ce serveur. `wikipedia `_. + +Une introduction à OAuth est `disponible ici `_. Elle introduit le protocole comme étant une `valet key`, une clé que l'on donne à la personne qui va garer votre voiture pendant que vous profitez des mondanités. Cette clé donne un accès à votre voiture, tout en bloquant un ensemble de fonctionnalités. Le principe du protocole est semblable en ce sens: vous vous réservez un accès total à une API, tandis que le système de jetons permet d'identifier une personne, tout en lui donnant un accès restreint à votre application. + +L'utilisation de jetons permet notamment de définir une durée d'utilisation et une portée d'utilisation. L'utilisateur d'un service A peut par exemple autoriser un service B à accéder à des ressources qu'il possède, sans pour autant révéler son nom d'utilisateur ou son mot de passe. + +L'exemple repris au niveau du `workflow `_ est le suivant : un utilisateur(trice), Jane, a uploadé des photos sur le site faji.com (A). Elle souhaite les imprimer au travers du site beppa.com (B). +Au moment de la commande, le site beppa.com envoie une demande au site faji.com pour accéder aux ressources partagées par Jane. Pour cela, une nouvelle page s'ouvre pour l'utilisateur, et lui demande d'introduire sa "pièce d'identité". Le site A, ayant reçu une demande de B, mais certifiée par l'utilisateur, ouvre alors les ressources et lui permet d'y accéder. \ No newline at end of file