Skip to content

Commit 1b002f9

Browse files
committed
bug fixes routes: edit, logout
1 parent f91c3e4 commit 1b002f9

File tree

3 files changed

+81
-51
lines changed

3 files changed

+81
-51
lines changed

api/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from flask import Flask
99
from flask_cors import CORS
1010

11-
from .routes import rest_api, jwt
11+
from .routes import rest_api
1212
from .models import db
1313

1414
app = Flask(__name__)
@@ -17,13 +17,13 @@
1717

1818
db.init_app(app)
1919
rest_api.init_app(app)
20-
jwt.init_app(app)
2120
CORS(app)
2221

2322
"""
2423
Custom responses
2524
"""
2625

26+
2727
@app.after_request
2828
def after_request(response):
2929
"""
@@ -33,7 +33,6 @@ def after_request(response):
3333
if int(response.status_code) >= 400:
3434
response_data = json.loads(response.get_data())
3535
if "errors" in response_data:
36-
_err_keys = response_data.keys()
3736
response_data = {"success": False,
3837
"msg": list(response_data["errors"].items())[0][1]}
3938
response.set_data(json.dumps(response_data))

api/models.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@
66
from datetime import datetime
77

88
import json
9-
from json import JSONEncoder
109

1110
from werkzeug.security import generate_password_hash, check_password_hash
1211
from flask_sqlalchemy import SQLAlchemy
1312

1413
db = SQLAlchemy()
1514

15+
1616
class Users(db.Model):
1717
id = db.Column(db.Integer(), primary_key=True)
1818
username = db.Column(db.String(32), nullable=False)
1919
email = db.Column(db.String(64), nullable=False)
2020
password = db.Column(db.Text())
21+
jwt_auth_active = db.Column(db.Boolean())
2122
date_joined = db.Column(db.DateTime(), default=datetime.utcnow)
2223

2324
def __repr__(self):
@@ -39,8 +40,11 @@ def update_email(self, new_email):
3940
def update_username(self, new_username):
4041
self.username = new_username
4142

42-
def update_email(self, new_email):
43-
self.email = new_email
43+
def check_jwt_auth_active(self):
44+
return self.jwt_auth_active
45+
46+
def set_jwt_auth_active(self, set_status):
47+
self.jwt_auth_active = set_status
4448

4549
@classmethod
4650
def get_by_id(cls, id):
@@ -51,7 +55,7 @@ def get_by_email(cls, email):
5155
return cls.query.filter_by(email=email).first()
5256

5357
def toDICT(self):
54-
58+
5559
cls_dict = {}
5660
cls_dict['_id'] = self.id
5761
cls_dict['username'] = self.username
@@ -61,15 +65,16 @@ def toDICT(self):
6165

6266
def toJSON(self):
6367

64-
return json.dumps( self.toDICT() )
68+
return json.dumps(self.toDICT())
69+
6570

6671
class JWTTokenBlocklist(db.Model):
6772
id = db.Column(db.Integer(), primary_key=True)
68-
jti = db.Column(db.String(36), nullable=False)
73+
jwt_token = db.Column(db.String(), nullable=False)
6974
created_at = db.Column(db.DateTime(), nullable=False)
7075

7176
def __repr__(self):
72-
return f"JTI {self.jti}"
77+
return f"Expired Token: {self.jwt_token}"
7378

7479
def save(self):
7580
db.session.add(self)

api/routes.py

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,19 @@
33
Copyright (c) 2019 - present AppSeed.us
44
"""
55

6-
from datetime import datetime, timezone
6+
from datetime import datetime, timezone, timedelta
77

8-
import json
8+
from functools import wraps
99

1010
from flask import request
11-
from flask_restx import Api, Resource, fields, abort
12-
from flask_jwt_extended import JWTManager, jwt_required, get_jwt, create_access_token, get_jwt_identity
11+
from flask_restx import Api, Resource, fields
12+
13+
import jwt
1314

1415
from .models import db, Users, JWTTokenBlocklist
16+
from .config import BaseConfig
1517

1618
rest_api = Api(version="1.0", title="Users API")
17-
jwt = JWTManager()
18-
19-
"""
20-
Helper function for revoking JWT token
21-
"""
22-
23-
24-
@jwt.token_in_blocklist_loader
25-
def check_if_token_revoked(jwt_header, jwt_payload):
26-
jti = jwt_payload["jti"]
27-
token = db.session.query(JWTTokenBlocklist.id).filter_by(jti=jti).scalar()
28-
return token is not None
2919

3020

3121
"""
@@ -49,6 +39,47 @@ def check_if_token_revoked(jwt_header, jwt_payload):
4939
logout_model = rest_api.model('LogoutModel', {"token": fields.String(required=True)})
5040

5141

42+
"""
43+
Helper function for JWT token required
44+
"""
45+
46+
def token_required(f):
47+
48+
@wraps(f)
49+
def decorator(*args, **kwargs):
50+
51+
token = None
52+
53+
if "authorization" in request.headers:
54+
token = request.headers["authorization"]
55+
56+
if not token:
57+
return {"success": False, "msg": "Valid JWT token is missing"}, 400
58+
59+
try:
60+
data = jwt.decode(token, BaseConfig.SECRET_KEY, algorithms=["HS256"])
61+
current_user = Users.get_by_email(data["email"])
62+
63+
if not current_user:
64+
return {"success": False,
65+
"msg": "Sorry. Wrong auth token. This user does not exist."}, 400
66+
67+
token_expired = db.session.query(JWTTokenBlocklist.id).filter_by(jwt_token=token).scalar()
68+
69+
if token_expired is not None:
70+
return {"success": False, "msg": "Token revoked."}, 400
71+
72+
if not current_user.check_jwt_auth_active():
73+
return {"success": False, "msg": "Token expired."}, 400
74+
75+
except:
76+
return {"success": False, "msg": "Token is invalid"}, 400
77+
78+
return f(current_user, *args, **kwargs)
79+
80+
return decorator
81+
82+
5283
"""
5384
Flask-Restx routes
5485
"""
@@ -80,7 +111,7 @@ def post(self):
80111
new_user.save()
81112

82113
return {"success": True,
83-
"userID" : new_user.id,
114+
"userID": new_user.id,
84115
"msg": "The user was successfully registered"}, 200
85116

86117

@@ -109,11 +140,14 @@ def post(self):
109140
"msg": "Sorry. Wrong credentials."}, 400
110141

111142
# create access token uwing JWT
112-
access_token = create_access_token(identity=_email)
143+
token = jwt.encode({'email': _email, 'exp': datetime.utcnow() + timedelta(minutes=30)}, BaseConfig.SECRET_KEY)
144+
145+
user_exists.set_jwt_auth_active(True)
146+
user_exists.save()
113147

114148
return {"success": True,
115-
"token": access_token,
116-
"user" : user_exists.toJSON() }, 200
149+
"token": token,
150+
"user": user_exists.toJSON()}, 200
117151

118152

119153
@rest_api.route('/api/users/edit')
@@ -123,28 +157,21 @@ class EditUser(Resource):
123157
"""
124158

125159
@rest_api.expect(user_edit_model)
126-
@jwt_required()
127-
def post(self):
128-
129-
user_email = get_jwt_identity()
130-
current_user = Users.get_by_email(user_email)
131-
132-
if not current_user:
133-
return {"success": False,
134-
"msg": "Sorry. Wrong auth token. This user does not exist."}, 400
160+
@token_required
161+
def post(self, current_user):
135162

136163
req_data = request.get_json()
137164

138165
_new_username = req_data.get("username")
139166
_new_email = req_data.get("email")
140167

141168
if _new_username:
142-
current_user.update_username(_new_username)
169+
self.update_username(_new_username)
143170

144171
if _new_email:
145-
current_user.update_email(_new_email)
172+
self.update_email(_new_email)
146173

147-
current_user.save()
174+
self.save()
148175

149176
return {"success": True}, 200
150177

@@ -156,18 +183,17 @@ class LogoutUser(Resource):
156183
"""
157184

158185
@rest_api.expect(logout_model, validate=True)
159-
@jwt_required()
160-
def post(self):
186+
@token_required
187+
def post(self, current_user):
161188

162-
user_email = get_jwt_identity()
163-
current_user = Users.get_by_email(user_email)
164-
165-
if not current_user:
166-
return {"success": False,
167-
"msg": "Sorry. Wrong auth token"}, 400
189+
req_data = request.get_json()
190+
_jwt_token = req_data.get("token")
168191

169-
jwt_block = JWTTokenBlocklist(jti=get_jwt()["jti"], created_at=datetime.now(timezone.utc))
192+
jwt_block = JWTTokenBlocklist(jwt_token=_jwt_token, created_at=datetime.now(timezone.utc))
170193
jwt_block.save()
171194

195+
self.set_jwt_auth_active(False)
196+
self.save()
197+
172198
return {"success": True,
173199
"msg": "JWT Token revoked successfully"}, 200

0 commit comments

Comments
 (0)