Skip to content

Instantly share code, notes, and snippets.

@jslvtr
Last active April 17, 2022 03:01
Show Gist options
  • Save jslvtr/139cf76db7132b53f2b20c5b6a9fa7ad to your computer and use it in GitHub Desktop.
Save jslvtr/139cf76db7132b53f2b20c5b6a9fa7ad to your computer and use it in GitHub Desktop.
Simple authentication with encryption using Flask and Python
"""
This file defines a User model and a Flask application, and implements authentication using encryption.
For more information, visit http://tecladocode.com/blog/learn-python-password-encryption-with-flask
"""
from flask import Flask, request, jsonify
from werkzeug.security import generate_password_hash, check_password_hash
import sqlite3
app = Flask(__name__)
class UserNotFoundError(Exception):
def __init__(self, message):
self.message = message
class User:
def __init__(self, username, password):
self.username = username
self.password = password
def save_to_db(self):
connection = sqlite3.connect('data.db')
cursor = connection.cursor()
try:
cursor.execute('INSERT INTO users (username, password) VALUES (?, ?)', (self.username, self.password))
except:
cursor.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, username TEXT, password TEXT)')
raise UserNotFoundError('The table `users` did not exist, but it was created. Run the registration again.')
finally:
connection.commit()
connection.close()
@classmethod
def find_by_username(cls, username):
connection = sqlite3.connect('data.db')
cursor = connection.cursor()
try:
data = cursor.execute('SELECT * FROM users WHERE username=?', (username,)).fetchone()
if data:
return cls(data[1], data[2])
finally:
connection.close()
@app.route('/register', methods=['POST'])
def register_user():
username = request.form['username']
password = request.form['password']
try:
User(username, generate_password_hash(password)).save_to_db()
except Exception as e:
return jsonify({'error': e.message}), 500
return jsonify({'message': 'User registered successfully'}), 201
@app.route('/login', methods=['POST'])
def login_user():
username = request.form['username']
password = request.form['password']
user = User.find_by_username(username)
if user and check_password_hash(user.password, password):
return jsonify({'message': 'Password is correct'}) # You'll want to return a token that verifies the user in the future
return jsonify({'error': 'User or password are incorrect'}), 401
if __name__ == '__main__':
app.run(debug=True)
@kirbyevanj
Copy link

Line 43 has an SQL injection vulnerability. Might want to use an ORM type interface to the database in the future

Copy link

ghost commented Feb 27, 2018

wouldn't this be hashing instead of encrypting?

@victordomingos
Copy link

@kirbyevanj, are you sure that line has a SQL injection vulnerability? According to the Python sqlite docs:

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print(c.fetchone())

In the code above, at line 43, @jslvtr is passing a one-item tuple containing the username. Isn't it the same as suggested by the documentation? He simply skips the creation of a variable for that tuple. I believe the important bit here is to use the ? notation instead of just building a string with the variables appended.

@victordomingos
Copy link

@makmoud98, yes. it is very common to use these term interchangeably, but actually this seems not to be encryption but hashing, as the password stored this way cannot be decrypted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment