· 6 years ago · Mar 10, 2019, 09:08 AM
1from os import environ
2from apppack.models import app
3
4if __name__ == '__main__':
5 app.run()
6
7import jwt
8import datetime
9import app, db, bcrypt
10import config
11
12
13class User(db.Model):
14 """ User Model for storing user related details """
15 __tablename__ = "ConfuUsers"
16
17 #__abstract__ = True
18 #id = db.Column(db.Integer, primary_key=True)
19
20 id = db.Column(db.Integer, primary_key=True, autoincrement=True)
21 email = db.Column(db.String(255), unique=True, nullable=False)
22 password = db.Column(db.String(255), nullable=False)
23 registered_on = db.Column(db.DateTime, nullable=False)
24 admin = db.Column(db.Boolean, nullable=False, default=False)
25
26
27 def __init__(self, email, password, admin=False):
28 self.email = email
29 self.password = bcrypt.generate_password_hash(
30 password, app.config.get('BCRYPT_LOG_ROUNDS')
31 ).decode()
32 self.registered_on = datetime.datetime.now()
33 self.admin = admin
34
35 def encode_auth_token(self, user_id):
36 """
37 Generates the Auth Token
38 :return: string
39 """
40 try:
41 payload = {
42 'exp': datetime.datetime.utcnow() + datetime.timedelta(days=1, seconds=500),
43 'iat': datetime.datetime.utcnow(),
44 'sub': user_id
45 }
46 return jwt.encode(
47 payload,
48 app.config.get('SECRET_KEY'),
49 algorithm='HS256'
50 )
51 except Exception as e:
52 return e
53
54 @staticmethod
55 def decode_auth_token(auth_token):
56 """
57 Validates the auth token
58 :param auth_token:
59 :return: integer|string
60 """
61 try:
62 payload = jwt.decode(auth_token, app.config.get('SECRET_KEY'))
63 is_blacklisted_token = BlacklistToken.check_blacklist(auth_token)
64 if is_blacklisted_token:
65 return 'Token blacklisted. Please log in again.'
66 else:
67 return payload['sub']
68 except jwt.ExpiredSignatureError:
69 return 'Signature expired. Please log in again.'
70 except jwt.InvalidTokenError:
71 return 'Invalid token. Please log in again.'
72
73
74class BlacklistToken(db.Model):
75 """
76 Token Model for storing JWT tokens
77
78 """
79 __tablename__ = 'blacklist_tokens'
80 # __abstract__ = True
81
82 id = db.Column(db.Integer, primary_key=True, autoincrement=True)
83 token = db.Column(db.String(500), unique=True, nullable=False)
84 blacklisted_on = db.Column(db.DateTime, nullable=False)
85
86 def __init__(self, token):
87 self.token = token
88 self.blacklisted_on = datetime.datetime.now()
89
90 def __repr__(self):
91 return '<id: token: {}'.format(self.token)
92
93 @staticmethod
94 def check_blacklist(auth_token):
95 # check whether auth token has been blacklisted
96 res = BlacklistToken.query.filter_by(token=str(auth_token)).first()
97 if res:
98 return True
99 else:
100 return False
101
102from flask import Blueprint, request, make_response, jsonify
103from flask.views import MethodView
104
105import bcrypt, db
106from apppack.models import User, BlacklistToken
107
108auth_blueprint = Blueprint('auth', __name__)
109
110
111class RegisterAPI(MethodView):
112 """
113 User Registration Resource
114
115 """
116 def post(self):
117 # get the post data
118 post_data = request.get_json()
119 # check if user already exists
120 user = User.query.filter_by(email=post_data.get('email')).all()
121 if not user:
122 try:
123 user = User(
124 email=post_data.get('email'),
125 password=post_data.get('password')
126 )
127 # insert the user
128 db.session.add(user)
129 db.session.commit()
130 # generate the auth token
131 auth_token = user.encode_auth_token(user.id)
132 responseObject = {
133 'status': 'success',
134 'message': 'Successfully registered.',
135 'auth_token': auth_token.decode()
136 }
137 return make_response(jsonify(responseObject)), 201
138 except Exception as e:
139 responseObject = {
140 'status': 'fail',
141 'message': 'Some error occurred. Please try again.'
142 }
143 return make_response(jsonify(responseObject)), 401
144 else:
145 responseObject = {
146 'status': 'fail',
147 'message': 'User already exists. Please Log in.',
148 }
149 return make_response(jsonify(responseObject)), 202
150
151 #-------------------------------------------------------------------- test
152
153 #post_data = request.get_json()
154 ## check if user already exists
155 #user = User(
156 # email=post_data.get('email'),
157 # password=post_data.get('password'),
158 # )
159 # # insert the user
160 #db.session.add(user)
161 #db.session.commit()
162 #responseObject = {
163 # 'status': 'success',
164 # 'message': 'Successfully registered.',
165 # 'auth_token': post_data.get('email')
166 # }
167 #return make_response(jsonify(responseObject)), 201
168
169 #-----------------------------------------------------------------------test
170
171class LoginAPI(MethodView):
172 """
173 User Login Resource
174 """
175 def post(self):
176 # get the post data
177 post_data = request.get_json()
178 try:
179 # fetch the user data
180 user = User.query.filter_by(
181 email=post_data.get('email')
182 ).first()
183 if user and bcrypt.check_password_hash(
184 user.password, post_data.get('password')
185 ):
186 auth_token = user.encode_auth_token(user.id)
187 if auth_token:
188 responseObject = {
189 'status': 'success',
190 'message': 'Successfully logged in.',
191 'auth_token': auth_token.decode()
192 }
193 return make_response(jsonify(responseObject)), 200
194 else:
195 responseObject = {
196 'status': 'fail',
197 'message': 'User does not exist.'
198 }
199 return make_response(jsonify(responseObject)), 404
200 except Exception as e:
201 print(e)
202 responseObject = {
203 'status': 'fail',
204 'message': 'Try again'
205 }
206 return make_response(jsonify(responseObject)), 500
207
208
209class UserAPI(MethodView):
210 """
211 User Resource
212 """
213 def get(self):
214 # get the auth token
215 auth_header = request.headers.get('Authorization')
216 if auth_header:
217 try:
218 auth_token = auth_header
219 #auth_token = auth_header.split(" ")[1]
220 except indexerror:
221 responseobject = {
222 'status': 'fail',
223 'message': 'bearer token malformed.'
224 }
225 return make_response(jsonify(responseobject)), 401
226 else:
227 auth_token = ''
228 if auth_token:
229 resp = User.decode_auth_token(auth_token)
230 if not isinstance(resp, str):
231 user = User.query.filter_by(id=resp).first()
232 responseObject = {
233 'status': 'success',
234 'data': {
235 'user_id': user.id,
236 'email': user.email,
237 'admin': user.admin,
238 'registered_on': user.registered_on
239 }
240 }
241 return make_response(jsonify(responseObject)), 200
242 responseObject = {
243 'status': 'fail',
244 'message': resp
245 }
246 return make_response(jsonify(responseObject)), 401
247 else:
248 responseObject = {
249 'status': 'fail',
250 'message': 'Provide a valid auth token.'
251 }
252 return make_response(jsonify(responseObject)), 401
253
254
255class LogoutAPI(MethodView):
256 """
257 Logout Resource
258 """
259 def post(self):
260 # get auth token
261 auth_header = request.headers.get('Authorization')
262 if auth_header:
263 auth_token = auth_header
264 #auth_token = auth_header.split(" ")
265 #auth_token = auth_header.split(" ")[1]
266 else:
267 auth_token = ''
268 if auth_token:
269 resp = User.decode_auth_token(auth_token)
270 if not isinstance(resp, str):
271 # mark the token as blacklisted
272 blacklist_token = BlacklistToken(token=auth_token)
273 try:
274 # insert the token
275 db.session.add(blacklist_token)
276 db.session.commit()
277 responseObject = {
278 'status': 'success',
279 'message': 'Successfully logged out.'
280 }
281 return make_response(jsonify(responseObject)), 200
282 except Exception as e:
283 responseObject = {
284 'status': 'fail',
285 'message': e
286 }
287 return make_response(jsonify(responseObject)), 200
288 else:
289 responseObject = {
290 'status': 'fail',
291 'message': resp
292 }
293 return make_response(jsonify(responseObject)), 401
294 else:
295 responseObject = {
296 'status': 'fail',
297 'message': 'Provide a valid auth token.'
298 }
299 return make_response(jsonify(responseObject)), 403
300
301# define the API resources
302registration_view = RegisterAPI.as_view('register_api')
303login_view = LoginAPI.as_view('login_api')
304user_view = UserAPI.as_view('user_api')
305logout_view = LogoutAPI.as_view('logout_api')
306
307# add Rules for API Endpoints
308auth_blueprint.add_url_rule(
309 '/auth/register',
310 view_func=registration_view,
311 methods=['POST']
312)
313auth_blueprint.add_url_rule(
314 '/auth/login',
315 view_func=login_view,
316 methods=['POST']
317)
318auth_blueprint.add_url_rule(
319 '/auth/status',
320 view_func=user_view,
321 methods=['GET']
322)
323auth_blueprint.add_url_rule(
324 '/auth/logout',
325 view_func=logout_view,
326 methods=['POST']
327)
328
329import os
330
331from flask import Flask
332from flask_bcrypt import Bcrypt
333from flask_sqlalchemy import SQLAlchemy
334from flask_cors import CORS
335from apppack.views import auth_blueprint
336
337application = Flask(__name__)
338application.config['SECRET_KEY'] = 'yn=xc5xfanBxb8tnx83xbefx8axe3xddEx17x06xc9x96x8ec|'
339CORS(application)
340app_settings = os.getenv(
341 'APP_SETTINGS',
342 '.config.DevelopmentConfig'
343)
344app.config.from_object(app_settings)
345bcrypt = Bcrypt(application)
346db = SQLAlchemy(application)
347
348application.register_blueprint(auth_blueprint)
349
350import os
351basedir = os.path.abspath(os.path.dirname(__file__))
352postgres_local_base = 'postgresql://confudb:123123123!@confudb.cusmbtiketg6.ap-south-1.rds.amazonaws.com/'
353
354database_name = 'confudb'
355#'postgresql://postgres:admin@localhost/'
356#'flask_jwt_auth'
357
358class BaseConfig:
359 """Base configuration."""
360 SECRET_KEY = os.getenv('SECRET_KEY', 'yn=xc5xfanBxb8tnx83xbefx8axe3xddEx17x06xc9x96x8ec|')
361 DEBUG = False
362 CSRF_ENABLED = True
363 BCRYPT_LOG_ROUNDS = 13
364 SQLALCHEMY_TRACK_MODIFICATIONS = False
365
366
367class DevelopmentConfig(BaseConfig):
368 """Development configuration."""
369 DEVELOPMENT = True
370 DEBUG = True
371 BCRYPT_LOG_ROUNDS = 4
372 SQLALCHEMY_DATABASE_URI = postgres_local_base + database_name
373
374
375class TestingConfig(BaseConfig):
376 """Testing configuration."""
377 # DEBUG = True
378 TESTING = True
379 BCRYPT_LOG_ROUNDS = 4
380 SQLALCHEMY_DATABASE_URI = postgres_local_base
381 PRESERVE_CONTEXT_ON_EXCEPTION = False
382
383
384class ProductionConfig(BaseConfig):
385 """Production configuration."""
386 SECRET_KEY = 'yn=xc5xfanBxb8tnx83xbefx8axe3xddEx17x06xc9x96x8ec|'
387 DEBUG = False
388 SQLALCHEMY_DATABASE_URI = 'postgresql//postgres:123123123!@confudb.cusmbtiketg6.ap-south-1.rds.amazonaws.com/confudb'