-
Notifications
You must be signed in to change notification settings - Fork 168
/
Copy pathauth_middleware.py
72 lines (65 loc) · 3.09 KB
/
auth_middleware.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from functools import wraps
import jwt
from flask import request, abort
from flask import current_app, g
from model.users import User
def token_required(roles=None):
'''
This function is used to guard API endpoints that require authentication.
Here is how it works:
1. checks for the presence of a valid JWT token in the request cookie
2. decodes the token and retrieves the user data
3. checks if the user data is found in the database
4. checks if the user has the required role
5. set the current_user in the global context (Flask's g object)
6. returns the decorated function if all checks pass
Here are some possible error responses:
A. 401 / Unauthorized: token is missing or invalid
B. 403 / Forbidden: user has insufficient permissions
C. 500 / Internal Server Error: something went wrong with the token decoding
'''
def decorator(func_to_guard):
@wraps(func_to_guard)
def decorated(*args, **kwargs):
token = request.cookies.get(current_app.config["JWT_TOKEN_NAME"])
if not token:
return {
"message": "Authentication Token is missing!",
"data": None,
"error": "Unauthorized"
}, 401
try:
# Decode the token and retrieve the user data
data = jwt.decode(token, current_app.config["SECRET_KEY"], algorithms=["HS256"])
current_user = User.query.filter_by(_uid=data["_uid"]).first()
if current_user is None:
return {
"message": "Invalid Authentication token!",
"data": None,
"error": "Unauthorized"
}, 401
# Check user has the required role, when role is required
if roles and current_user.role not in roles:
return {
"message": "Insufficient permissions. Required roles: {}".format(roles),
"data": None,
"error": "Forbidden"
}, 403
# Success finding user and (optional) role
# Set the current_user in the global context
# Flask's g object is a global object that lasts for the duration of the request
# The g.current_user can be referenced in decorated function
g.current_user = current_user
# Error exception is for unknown jwt.decode errors
except Exception as e:
return {
"message": "Something went wrong decoding the token!",
"data": None,
"error": str(e)
}, 500
# Success, return to the decorated function
# func_to_guard is the function with the @token_required
# func_to_guard returns with the original function arguments
return func_to_guard(*args, **kwargs)
return decorated
return decorator