Exemple API avec contrôle accès manuel

This commit is contained in:
Emmanuel Viennet 2021-12-21 00:10:51 +01:00
parent 58cacb67b8
commit 06ca136384
4 changed files with 61 additions and 17 deletions

View File

@ -1,6 +1,7 @@
# -*- coding: UTF-8 -* # -*- coding: UTF-8 -*
# Authentication code borrowed from Miguel Grinberg's Mega Tutorial # Authentication code borrowed from Miguel Grinberg's Mega Tutorial
# (see https://github.com/miguelgrinberg/microblog) # (see https://github.com/miguelgrinberg/microblog)
# and modified for ScoDoc
# Under The MIT License (MIT) # Under The MIT License (MIT)
@ -23,6 +24,7 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from flask import g
from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth from flask_httpauth import HTTPBasicAuth, HTTPTokenAuth
from app.auth.models import User from app.auth.models import User
from app.api.errors import error_response from app.api.errors import error_response
@ -35,6 +37,7 @@ token_auth = HTTPTokenAuth()
def verify_password(username, password): def verify_password(username, password):
user = User.query.filter_by(user_name=username).first() user = User.query.filter_by(user_name=username).first()
if user and user.check_password(password): if user and user.check_password(password):
g.current_user = user
return user return user
@ -45,7 +48,9 @@ def basic_auth_error(status):
@token_auth.verify_token @token_auth.verify_token
def verify_token(token): def verify_token(token):
return User.check_token(token) if token else None user = User.check_token(token) if token else None
g.current_user = user
return user
@token_auth.error_handler @token_auth.error_handler
@ -53,15 +58,20 @@ def token_auth_error(status):
return error_response(status) return error_response(status)
def token_permission_required(permission): @token_auth.get_user_roles
def decorator(f): def get_user_roles(user):
@wraps(f) return user.roles
def decorated_function(*args, **kwargs):
scodoc_dept = getattr(g, "scodoc_dept", None)
if not current_user.has_permission(permission, scodoc_dept):
abort(403)
return f(*args, **kwargs)
return login_required(decorated_function)
return decorator # def token_permission_required(permission):
# def decorator(f):
# @wraps(f)
# def decorated_function(*args, **kwargs):
# scodoc_dept = getattr(g, "scodoc_dept", None)
# if not current_user.has_permission(permission, scodoc_dept):
# abort(403)
# return f(*args, **kwargs)
# return login_required(decorated_function)
# return decorator

View File

@ -39,13 +39,18 @@
# Scolarite/Notes/moduleimpl_status # Scolarite/Notes/moduleimpl_status
# Scolarite/setGroups # Scolarite/setGroups
from flask import jsonify, request, url_for, abort from flask import jsonify, request, url_for, abort, g
from app import db from flask_login import current_user
from sqlalchemy.sql import func
from app import db, log
from app.api import bp from app.api import bp
from app.api.auth import token_auth from app.api.auth import token_auth
from app.api.errors import bad_request from app.api.errors import bad_request, error_response
from app.decorators import permission_required
from app import models from app import models
from app.models import FormSemestre, FormSemestreInscription, Identite
from app.scodoc.sco_permissions import Permission
@bp.route("list_depts", methods=["GET"]) @bp.route("list_depts", methods=["GET"])
@ -54,3 +59,23 @@ def list_depts():
depts = models.Departement.query.filter_by(visible=True).all() depts = models.Departement.query.filter_by(visible=True).all()
data = [d.to_dict() for d in depts] data = [d.to_dict() for d in depts]
return jsonify(data) return jsonify(data)
@bp.route("/etudiants/courant", methods=["GET"])
@token_auth.login_required
def etudiants():
"""Liste de tous les étudiants actuellement inscrits à un semestre
en cours.
"""
# Vérification de l'accès: permission Observateir sur tous les départements
# (c'est un exemple à compléter)
if not g.current_user.has_permission(Permission.ScoObservateur, None):
return error_response(401, message="accès interdit")
query = db.session.query(Identite).filter(
FormSemestreInscription.formsemestre_id == FormSemestre.id,
FormSemestreInscription.etudid == Identite.id,
FormSemestre.date_debut <= func.now(),
FormSemestre.date_fin >= func.now(),
)
return jsonify([e.to_dict_bul(include_photo=False) for e in query])

View File

@ -272,7 +272,7 @@ class User(UserMixin, db.Model):
"""string repr. of user's roles (with depts) """string repr. of user's roles (with depts)
e.g. "Ens_RT, Ens_Info, Secr_CJ" e.g. "Ens_RT, Ens_Info, Secr_CJ"
""" """
return ",".join(f"{r.role.name}_{r.dept or ''}" for r in self.user_roles) return ",".join(f"{r.role.name or ''}_{r.dept or ''}" for r in self.user_roles)
def is_administrator(self): def is_administrator(self):
"True if i'm an active SuperAdmin" "True if i'm an active SuperAdmin"

View File

@ -2,7 +2,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Exemple utilisation API ScoDoc 9 avec jeton obtenu par basic athentication """Exemple utilisation API ScoDoc 9 avec jeton obtenu par basic authentication
Utilisation: créer les variables d'environnement: (indiquer les valeurs Utilisation: créer les variables d'environnement: (indiquer les valeurs
@ -80,6 +80,15 @@ if r.status_code != 200:
pp(r.json()) pp(r.json())
# Liste des tous les étudiants en cours (de tous les depts)
r = requests.get(
SCODOC_URL + "/ScoDoc/api/etudiants/courant",
headers=HEADERS,
verify=CHECK_CERTIFICATE,
)
if r.status_code != 200:
raise ScoError("erreur de connexion: vérifier adresse et identifiants")
# # --- Recupere la liste de tous les semestres: # # --- Recupere la liste de tous les semestres:
# sems = GET(s, "Notes/formsemestre_list?format=json", "Aucun semestre !") # sems = GET(s, "Notes/formsemestre_list?format=json", "Aucun semestre !")