├── .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 |
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 |
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 |
--------------------------------------------------------------------------------