Finished auth

This commit is contained in:
Verox 2024-01-12 16:53:03 +01:00
parent 47d549be85
commit b3b8a3fd5f
7 changed files with 133 additions and 33 deletions

91
app.py
View File

@ -1,12 +1,30 @@
import datetime
import hashlib
from flask import Flask, render_template, redirect, url_for, request
from flask_login import login_required, LoginManager
from flask_login import login_required, LoginManager, login_user, logout_user, current_user
from models.User import User
from utils import anonymous_required
# Create a new Flask instance
app = Flask(__name__)
app.secret_key = 'PSSSSSHHHT!'
# Initialize the Flask-Login extension
login_manager = LoginManager()
login_manager.login_view = 'login'
login_manager.init_app(app)
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
@app.context_processor
def inject_user():
return dict(user=current_user)
# Create a new route
@ -15,20 +33,25 @@ def index():
# return 'Hello World'
return render_template('index.html', title='Home', utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M:%S"))
@app.route('/test')
@login_required
def secret():
return 'Pssst!'
@app.route('/login')
@anonymous_required
def login():
return render_template('auth/login.html')
return render_template('auth/login.html', errors={})
@app.route('/signup')
@anonymous_required
def signup():
return render_template('auth/signup.html', errors={})
@app.route('/signup', methods=['POST'])
def signup_post():
email = request.form.get('email')
@ -44,36 +67,66 @@ def signup_post():
if not password:
errors['password'] = 'Password is required.'
return render_template(
'auth/signup.html',
email=email,
name=name,
password=password,
errors=errors
)
if errors:
return render_template(
'auth/signup.html',
email=email,
name=name,
password=password,
errors=errors
)
# Save user to database. Maybe log the user in directly.
user = User.create(name, email, password)
login_user(user)
# Redirect to login page
return redirect(url_for('login'))
return redirect(url_for('secret'))
@app.route('/login', methods=['POST'])
def login_post():
email = request.form.get('email')
password = request.form.get('password')
# Check for errors
errors = {}
if not email:
errors['email'] = 'Email is required.'
if not password:
errors['password'] = 'Password is required.'
# Check if user exists
user = User.get_by_email(email)
if not user:
errors['email'] = 'User does not exist.'
elif user.password is None or hashlib.sha256(password.encode()).hexdigest() != user.password:
errors['password'] = 'Password incorrect.'
if errors:
return render_template(
'auth/login.html',
email=email,
password=password,
errors=errors
)
login_user(user)
# Redirect to login page
return redirect(url_for('secret'))
@app.route('/logout')
@login_required
def logout():
# Log out functionality
logout_user()
return redirect(url_for('index'))
# Run the application
if __name__ == '__main__':
login_manager = LoginManager()
login_manager.login_view = 'login'
login_manager.init_app(app)
app.secret_key = 'PSSSSSHHHT!'
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
app.run(port=5000, debug=True)

View File

@ -1,3 +1,4 @@
from datetime import datetime
import hashlib
import sqlite3
@ -7,9 +8,11 @@ def con3():
return conn
def create_user(name, email, password):
password = hashlib.md5(password.encode()).hexdigest()
query = f"INSERT INTO users (name, email, password) VALUES ({name}, {email}, {password})"
def create_user(name: str, email: str, password: str):
password = hashlib.sha256(password.encode()).hexdigest()
now = datetime.now().isoformat()
query = (f"INSERT INTO users (name, email, password, created_at, updated_at) VALUES ('{name}', '{email}', "
f"'{password}', '{now}', '{now}');")
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
@ -18,8 +21,18 @@ def create_user(name, email, password):
return cursor.lastrowid
def get_user(id):
query = f"SELECT * FROM users WHERE id = {id}"
def get_user(id: int):
query = f"SELECT * FROM users WHERE id = {id};"
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
user = cursor.fetchone()
conn.close()
return user
def get_user_by_email(email: str):
query = f"SELECT * FROM users WHERE email = '{email}';"
conn = con3()
cursor = conn.cursor()
cursor.execute(query)

Binary file not shown.

View File

@ -1,18 +1,26 @@
from db.SQLiteClient import create_user, get_user
from flask_login import UserMixin
from db.SQLiteClient import create_user, get_user, get_user_by_email
class User:
def __init__(self, id, name, email):
class User(UserMixin):
def __init__(self, id, name, email, password=None):
self.id = id
self.name = name
self.email = email
self.password = password
@staticmethod
def create(name, email, password):
def create(name: str, email: str, password: str):
id = create_user(name, email, password)
return User(id, name, email)
@staticmethod
def get(id):
def get(id: int):
user = get_user(id)
return User(user[0], user[1], user[2]) if user else None
return User(user[0], user[1], user[2], user[3]) if user else None
@staticmethod
def get_by_email(email: str):
user = get_user_by_email(email)
return User(user[0], user[1], user[2], user[3]) if user else None

View File

@ -8,19 +8,25 @@
<div class="mb-3 row">
<label for="email" class="col-sm-2 col-form-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="email" placeholder="email@example.com">
<input type="email" value="{{ email }}" class="form-control {% if errors.get('email') %} is-invalid {% endif %}" id="email" placeholder="email@example.com" name="email">
<div class="invalid-feedback">
{{ errors.get('email', '') }}
</div>
</div>
</div>
<div class="mb-3 row">
<label for="password" class="col-sm-2 col-form-label">Passwort</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="password">
<input type="password" value="{{ password }}" class="form-control {% if errors.get('password') %} is-invalid {% endif %}" id="password" name="password">
<div class="invalid-feedback">
{{ errors.get('password', '') }}
</div>
</div>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary mb-3">Einloggen</button>
<button type="submit" class="btn btn-primary mb-3">Login</button>
</div>
</form>
</div>

View File

@ -36,12 +36,18 @@
</li>
</ul>
<ul class="navbar-nav mb-2 mb-lg-0">
{% if not current_user.is_authenticated %}
<li class="nav-item me-2">
<a class="btn btn-primary" aria-current="page" href="{{ url_for('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="btn btn-outline-secondary" aria-current="page" href="{{ url_for('signup') }}">Signup</a>
</li>
{% else %}
<li class="nav-item me-2">
<a class="btn btn-primary" aria-current="page" href="{{ url_for('logout') }}">Logout</a>
</li>
{% endif %}
</ul>
</div>
</div>

14
utils.py Normal file
View File

@ -0,0 +1,14 @@
from functools import wraps
from flask import redirect, url_for
from flask_login import current_user
def anonymous_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if current_user.is_authenticated:
return redirect(url_for('index'))
return f(*args, **kwargs)
return decorated_function