Last active
April 17, 2022 03:01
-
-
Save jslvtr/139cf76db7132b53f2b20c5b6a9fa7ad to your computer and use it in GitHub Desktop.
Simple authentication with encryption using Flask and Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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) |
wouldn't this be hashing instead of encrypting?
@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.
@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
Line 43 has an SQL injection vulnerability. Might want to use an ORM type interface to the database in the future