Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import datetime
- from flask import jsonify, make_response, request
- import MySQLdb
- from werkzeug.security import check_password_hash
- import jwt
- from functools import wraps
- # token_required function that will be used as the @token_required decorator
- def token_required(f):
- @wraps(f)
- def decorated(*args, **kwargs):
- token = None
- # Check for the token in the requests headers
- if 'x-access-token' in request.headers:
- token = request.headers['x-access-token']
- # If there's no token in the request, return a 401
- if not token:
- return jsonify({'message' : 'Token is missing!'}), 401
- try:
- # Decode the token using the app's secret key
- data = jwt.decode(token, app.config['SECRET_KEY'])
- #
- try:
- dbconn=MySQLdb.connect(database=dbname, user=dbuser, password=dbpass, host=dbhost)
- cursor = dbconn.cursor()
- # Instead of a query, it's cleaner to create a procedure in your database to get a user using the public_id
- # Then call the procedure and provide the public_userid from the token
- cursor.callproc('userGetUserByPublicID',[data['public_userid']])
- current_user = User(cursor.fetchone())
- cursor.close()
- dbconn.close()
- except Exception as e:
- error = "ERROR: " + str(e)
- return error
- except:
- # If token could not be decoded, return a 401
- return jsonify({'message' : 'Token is invalid!'}), 401
- return f(current_user, *args, **kwargs)
- return decorated
- # Now underneath other routes in your Flask app
- # You can add a @token_required decorator
- # Example:
- ###########################################################
- # @app.route('/user/profile/<profile_id>', methods=['GET'])
- # @token_required()
- ###########################################################
- # To access a route with the @token_required() decorator
- # First use basic auth to access the login route '/user/standard/login'
- # Then take the token returned and place it in the header of a request to a @token_required() route like below:
- # {'x-access-token':'token goes here'}
- # The request to this route just needs to contain Basic Auth details (username and password)
- # The route will return a token that can be reused for 8 hours to authenticate
- @app.route('/user/standard/login')
- def login():
- # Access the credentials provided in the request using request.authorization
- # auth.username and auth.password will contain the username and password provided
- auth = request.authorization
- # If username or password is not provided, return a 401
- if not auth or not auth.username or not auth.password:
- return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login required!"'})
- # Check against the user table to see if the user exists
- try:
- # Use globally set database credentials, preferably read in from a secure file(s)
- dbconn=MySQLdb.connect(database=dbname, user=dbuser, password=dbpass, host=dbhost)
- cursor = dbconn.cursor()
- # Instead of a query, it's cleaner to create a procedure in your database to get a user using the username
- # Then call the procedure and provide the username provided
- cursor.callproc('userGetUserByUsername',[auth.username])
- user = User(cursor.fetchone())
- cursor.close()
- dbconn.close()
- except Exception as e:
- error = "ERROR: " + str(e)
- return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login required!"'})
- # If the username does not exist, return a 401
- if not user:
- return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login required!"'})
- # Check if the password provided matches the hashed password in the database
- if check_password_hash(user.password, auth.password):
- # If the passwords match, create a token using the package jwt and encoded using the apps secret key
- # Token will contain the user's ID and an expiration date 8 hours in the future
- token = jwt.encode({'public_userid' : user.public_userid, 'exp' : datetime.datetime.utcnow() + datetime.timedelta(hours=8)}, app.config['SECRET_KEY'])
- # Return the token in a json object to be stored by the client and used for subsequent authentication
- return jsonify({'token' : token.decode('UTF-8')})
- # If the passwords do not match, return a 401
- return make_response('Could not verify', 401, {'WWW-Authenticate' : 'Basic realm="Login required!"'})
Add Comment
Please, Sign In to add comment