├── .gitignore ├── database.db ├── templates ├── dashboard.html ├── home.html ├── login.html └── register.html ├── requirements.txt ├── README.md ├── LICENSE └── app.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | flask-env -------------------------------------------------------------------------------- /database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neupanic/Python-Flask-Authentication-Tutorial/HEAD/database.db -------------------------------------------------------------------------------- /templates/dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Dashboard 9 | 10 | 11 | 12 |

Hello you are logged in.

13 | Press here to logout 14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Home 9 | 10 | 11 | 12 |

Login Authentication System in Flask.

13 | Login Page
14 | Register Page
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.5.0 2 | bcrypt==3.2.0 3 | cffi==1.15.0 4 | click==8.1.2 5 | dnspython==2.2.1 6 | email-validator==1.1.3 7 | Flask==2.1.1 8 | Flask-Bcrypt==1.0.1 9 | Flask-Login==0.6.0 10 | Flask-SQLAlchemy==2.5.1 11 | Flask-WTF==1.0.1 12 | greenlet==1.1.2 13 | idna==3.3 14 | importlib-metadata==4.11.3 15 | itsdangerous==2.1.2 16 | Jinja2==3.1.1 17 | MarkupSafe==2.1.1 18 | pycparser==2.21 19 | six==1.16.0 20 | SQLAlchemy==1.4.35 21 | sqlparse==0.4.2 22 | Werkzeug==2.1.1 23 | WTForms==3.0.1 24 | zipp==3.8.0 25 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Login 9 | 10 | 11 | 12 |

Login Page

13 | 14 |
15 | {{ form.hidden_tag() }} 16 | {{ form.username }} 17 | {{ form.password }} 18 | {{ form.submit }} 19 |
20 | 21 | Don't have an account? Sign Up 22 | 23 | 24 | -------------------------------------------------------------------------------- /templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Register 9 | 10 | 11 | 12 |

Register Page

13 | 14 |
15 | {{ form.hidden_tag() }} 16 | {{ form.username }} 17 | {{ form.password }} 18 | {{ form.submit }} 19 |
20 | 21 | Already have an account? Log In 22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Flask Authentication 2 | 3 | This repository contains the code used in the Python Flask Authentication [video](https://www.youtube.com/watch?v=71EU8gnZqZQ) uploaded on [my YouTube channel](https://www.youtube.com/watch?v=71EU8gnZqZQ). 4 | 5 | ## Installation 6 | 7 | Use the package manager [pip](https://pip.pypa.io/en/stable/) to install the required dependencies 8 | 9 | ##### Windows: 10 | ```zsh 11 | pip install -r requirements.txt 12 | ``` 13 | 14 | ##### macOS/Linux: 15 | ```zsh 16 | pip3 install -r requirements.txt 17 | ``` 18 | 19 | ## Usage 20 | 21 | ##### Windows: 22 | ```zsh 23 | python app.py 24 | ``` 25 | ##### macOS/Linux: 26 | ```zsh 27 | python3 app.py 28 | ``` 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Arpan Neupane 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, url_for, redirect 2 | from flask_sqlalchemy import SQLAlchemy 3 | from flask_login import UserMixin, login_user, LoginManager, login_required, logout_user, current_user 4 | from flask_wtf import FlaskForm 5 | from wtforms import StringField, PasswordField, SubmitField 6 | from wtforms.validators import InputRequired, Length, ValidationError 7 | from flask_bcrypt import Bcrypt 8 | 9 | app = Flask(__name__) 10 | db = SQLAlchemy(app) 11 | bcrypt = Bcrypt(app) 12 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' 13 | app.config['SECRET_KEY'] = 'thisisasecretkey' 14 | 15 | 16 | login_manager = LoginManager() 17 | login_manager.init_app(app) 18 | login_manager.login_view = 'login' 19 | 20 | 21 | @login_manager.user_loader 22 | def load_user(user_id): 23 | return User.query.get(int(user_id)) 24 | 25 | 26 | class User(db.Model, UserMixin): 27 | id = db.Column(db.Integer, primary_key=True) 28 | username = db.Column(db.String(20), nullable=False, unique=True) 29 | password = db.Column(db.String(80), nullable=False) 30 | 31 | 32 | class RegisterForm(FlaskForm): 33 | username = StringField(validators=[ 34 | InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) 35 | 36 | password = PasswordField(validators=[ 37 | InputRequired(), Length(min=8, max=20)], render_kw={"placeholder": "Password"}) 38 | 39 | submit = SubmitField('Register') 40 | 41 | def validate_username(self, username): 42 | existing_user_username = User.query.filter_by( 43 | username=username.data).first() 44 | if existing_user_username: 45 | raise ValidationError( 46 | 'That username already exists. Please choose a different one.') 47 | 48 | 49 | class LoginForm(FlaskForm): 50 | username = StringField(validators=[ 51 | InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) 52 | 53 | password = PasswordField(validators=[ 54 | InputRequired(), Length(min=8, max=20)], render_kw={"placeholder": "Password"}) 55 | 56 | submit = SubmitField('Login') 57 | 58 | 59 | @app.route('/') 60 | def home(): 61 | return render_template('home.html') 62 | 63 | 64 | @app.route('/login', methods=['GET', 'POST']) 65 | def login(): 66 | form = LoginForm() 67 | if form.validate_on_submit(): 68 | user = User.query.filter_by(username=form.username.data).first() 69 | if user: 70 | if bcrypt.check_password_hash(user.password, form.password.data): 71 | login_user(user) 72 | return redirect(url_for('dashboard')) 73 | return render_template('login.html', form=form) 74 | 75 | 76 | @app.route('/dashboard', methods=['GET', 'POST']) 77 | @login_required 78 | def dashboard(): 79 | return render_template('dashboard.html') 80 | 81 | 82 | @app.route('/logout', methods=['GET', 'POST']) 83 | @login_required 84 | def logout(): 85 | logout_user() 86 | return redirect(url_for('login')) 87 | 88 | 89 | @ app.route('/register', methods=['GET', 'POST']) 90 | def register(): 91 | form = RegisterForm() 92 | 93 | if form.validate_on_submit(): 94 | hashed_password = bcrypt.generate_password_hash(form.password.data) 95 | new_user = User(username=form.username.data, password=hashed_password) 96 | db.session.add(new_user) 97 | db.session.commit() 98 | return redirect(url_for('login')) 99 | 100 | return render_template('register.html', form=form) 101 | 102 | 103 | if __name__ == "__main__": 104 | app.run(debug=True) 105 | --------------------------------------------------------------------------------