diff --git a/README.md b/README.md index 4c19bf6..3555e55 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,18 @@ # Appli_demo +Petite app utilisant l'authentification avec une génération de token jwt. + +## Installation et prérequis +Le projet est codé en Python3 il est donc necessaire d'avoir Python3 d'installer sur sa machine. Pour vérifier si +Python3 est bien installer `python3 --version` + +Dans un terminal utiliser `pip install -r requirements.txt` (_de préférence dans un environement +virtuel_) afin d'installer les librairies necessaires au bon fonctionnement du projet. + +## Lancement du projet +Ensuite ouvrez deux terminal et placer vous à la racine du projet. + +Dans le premier taper `flask run` afin de lancer le serveur web. + +Et dans l'autre `python3 requetes.py` afin de lancer une batterie de requête pour vérifier le bon +fonctionnement du projet. diff --git a/app.py b/app.py new file mode 100644 index 0000000..1d617b0 --- /dev/null +++ b/app.py @@ -0,0 +1,146 @@ +from flask import Flask, request, jsonify, make_response, session, render_template, abort +from flask_restful import Api, Resource +import jwt +from datetime import datetime, timedelta +from functools import wraps + +app = Flask(__name__) + +app.config['SECRET_KEY'] = 'secret' + +api = Api(app) + +classes = {'1': + { + 'nom': 'A1', + 'nombre_eleve': '15', + 'eleves': { + '1': ['Mariue', 'Julien', '12'], + '2': ['Koene', 'Morice', '13'], + '3': ['Moatir', 'Pierre', '12'], + '4': ['Poiti', 'Marc', '12'], + '5': ['Areop', 'Tome', '12'], + '6': ['Cenois', 'Louis', '13'], + '7': ['Quotine', 'Maxime', '12'], + '8': ['Reval', 'Adrien', '12'], + '9': ['Fonduri', 'Juliette', '11'], + '10': ['Graconti', 'Marie', '12'], + '11': ['Henvio', 'Louise', '12'], + '12': ['Kenano', 'Bertran', '14'], + '13': ['Vertille', 'Jean-Pierre', '12'], + '14': ['Provern', 'Jean', '14'], + '15': ['Secinoi', 'Celine', '12'], + } + }, + '2': + { + 'nom': 'A2', + 'nombre_eleve': '5', + 'eleves': { + '1': ['Benar', 'Leo', '15'], + '2': ['Grovin', 'Benois', '16'], + '3': ['Xeroi', 'Amelie', '15'], + '4': ['Amonie', 'Julien', '14'], + '5': ['Surois', 'Camille', '15'] + } + } +} + + +def token_required(func): + @wraps(func) + def decorated(*args, **kwargs): + + token = None + if 'token' in request.headers: + token = request.headers['token'] + + if not token: + return jsonify({'Alert!': 'Pas de Token!'}) + # abort(403, 'pas de token') + try: + payload = jwt.decode(token, app.config['SECRET_KEY']) + except: + # abort(403, 'token invalid') + return make_response(jsonify({'Alert!': 'Token invalid!'})) + + return func(*args, **kwargs) + + return decorated + + +@app.route('/') +def home(): + if not session.get('logged_in'): + return render_template('login.html') + else: + return 'Déjà connecté' + + +@app.route('/public') +def public(): + return 'Vous êtes bien sur la page public !' + + +@app.route('/auth', methods=['GET']) +@token_required +def auth(): + return 'Vous êtes bien sur la page auth !' + + +@app.route('/login', methods=['POST']) +def login(): + if request.form['username'] and request.form['password'] == '123': + session['logged_in'] = True + token = jwt.encode({ + 'user': 0 + # 'expiration': str(datetime.utcnow() + timedelta(seconds=30)) + }, + app.config['SECRET_KEY'], algorithm="HS256") + return jsonify({'token': token.decode('utf-8')}) + else: + return make_response('Unable to verify', 403, {'WWW-Authenticate': 'Basic realm:"Authentication Failed!'}) + + +class Classes(Resource): + @token_required + def get(self): + return classes + + @token_required + def post(self): + return classes + + +api.add_resource(Classes, "/classes") + + +class Classe(Resource): + @token_required + def get(self, id_classe): + return classes[id_classe] + + @token_required + def post(self, id_classe): + return classes[id_classe] + + +api.add_resource(Classe, "/classes/") + + +class Eleve(Resource): + @token_required + def get(self, id_classe, id_eleve): + return classes[id_classe]['eleves'][id_eleve] + + @token_required + def post(self, id_classe, id_eleve): + return classes[id_classe]['eleves'][id_eleve] + + +api.add_resource(Eleve, "//") + + +@app.route("/reset") +def reset(): + session.clear() diff --git a/model/data.py b/model/data.py new file mode 100644 index 0000000..f67851f --- /dev/null +++ b/model/data.py @@ -0,0 +1,35 @@ +# data = {'1': +# { +# 'nom': 'A1', +# 'nombre_eleve': '15', +# 'eleves': { +# '1': ['Mariue', 'Julien', '12'], +# '2': ['Koene', 'Morice', '13'], +# '3': ['Moatir', 'Pierre', '12'], +# '4': ['Poiti', 'Marc', '12'], +# '5': ['Areop', 'Tome', '12'], +# '6': ['Cenois', 'Louis', '13'], +# '7': ['Quotine', 'Maxime', '12'], +# '8': ['Reval', 'Adrien', '12'], +# '9': ['Fonduri', 'Juliette', '11'], +# '10': ['Graconti', 'Marie', '12'], +# '11': ['Henvio', 'Louise', '12'], +# '12': ['Kenano', 'Bertran', '14'], +# '13': ['Vertille', 'Jean-Pierre', '12'], +# '14': ['Provern', 'Jean', '14'], +# '15': ['Secinoi', 'Celine', '12'], +# } +# }, +# '2': +# { +# 'nom': 'A2', +# 'nombre_eleve': '5', +# 'eleve': { +# '1': ['Benar', 'Leo', '15'], +# '2': ['Grovin', 'Benois', '16'], +# '3': ['Xeroi', 'Amelie', '15'], +# '4': ['Amonie', 'Julien', '14'], +# '5': ['Surois', 'Camille', '15'] +# } +# } +# } diff --git a/requetes.py b/requetes.py new file mode 100644 index 0000000..a28a719 --- /dev/null +++ b/requetes.py @@ -0,0 +1,60 @@ +import requests + +BASE = "http://127.0.0.1:5000/" + +login = requests.post(BASE + 'login', {'username': 'leo', 'password': '123'}) + +token = login.json()['token'] + +print('Génération du token par une authentification correct: ') +print(token) +print("\n") + +HEADERS = {"Authorization": f"Bearer {token}", 'token': token} + +public = requests.get(BASE + "public") +print('Accès à la page public qui ne nécessite pas de token: ') +print(public.text) +print("\n") + +auth = requests.get(BASE + 'auth', headers=HEADERS) +print('Accès à la page auth qui nécessite un token valide: ') +print(auth.text) +print("\n") + +classes = requests.get(BASE + "classes", headers=HEADERS) +print("Les classes : ") +print(classes.json()) +print("\n") + +classes1 = requests.get(BASE + "classes/1", headers=HEADERS) +print("La classe 1 : ") +print(classes1.json()) +print("\n") + +eleve = requests.get(BASE + "2/5", headers=HEADERS) +print("L'eleve 5 de la classe 2 : ") +print(eleve.json()) +print("\n") + +requests.get(BASE + 'reset') +print('Reset de la session pour supprimer le token...') + +login2 = requests.post(BASE + 'login', {'username': 'leo', 'password': 'azerty'}) + +print('Login avec un password qui ne générera pas de token... ') +print("\n") + +public2 = requests.get(BASE + "public") +print('Accès à la page public qui ne nécessite pas de token: ') +print(public2.text) +print("\n") + +auth2 = requests.get(BASE + 'auth') +print('Accès à la page auth qui nécessite un token valide: ') +print(auth2.json()) +print("\n") + + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ecab08c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,44 @@ +aniso8601==9.0.1 +anyio==3.3.4 +api==0.0.7 +attrs==21.2.0 +auth==0.5.3 +blinker==1.4 +certifi==2021.10.8 +charset-normalizer==2.0.7 +click==8.0.3 +dnspython==2.1.0 +eventlet==0.32.0 +falcon==3.0.1 +fastapi==0.70.0 +Flask==2.0.2 +Flask-HTTPAuth==4.5.0 +Flask-JWT==0.3.2 +Flask-RESTful==0.3.9 +greenlet==1.1.2 +gunicorn==20.1.0 +idna==3.3 +itsdangerous==2.0.1 +Jinja2==3.0.2 +JsonForm==0.0.2 +jsonschema==4.1.2 +JsonSir==0.0.2 +MarkupSafe==2.0.1 +mongoengine==0.23.1 +nose==1.3.7 +pydantic==1.8.2 +PyJWT==1.4.2 +pymongo==3.12.1 +pyrsistent==0.18.0 +python-dotenv==0.19.1 +Python-EasyConfig==0.1.7 +pytz==2021.3 +PyYAML==6.0 +requests==2.26.0 +Resource==0.2.1 +six==1.16.0 +sniffio==1.2.0 +starlette==0.16.0 +typing-extensions==3.10.0.2 +urllib3==1.26.7 +Werkzeug==2.0.2 diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..b6bf635 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,12 @@ + + + + + {{ title }} + + +

Mini-App classe

+{% block content %} +{% endblock %} + + \ No newline at end of file diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..44ca008 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} +{% block content %} +
+ +

+ + +

+ + +
+{% endblock %} \ No newline at end of file