In this tutorial, we will be going over how to implement authentication in a Flask application using the Flask-Login extension. Flask-Login provides user session management, handling user login and logout, and protecting routes that require authentication.
To get started, make sure you have Flask installed. You can install Flask using pip:
pip install Flask
Next, install Flask-Login:
pip install Flask-Login
Now let’s create a new Flask app and configure Flask-Login.
from flask import Flask, render_template, redirect, url_for
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key_here'
login_manager = LoginManager()
login_manager.init_app(app)
In the code above, we import Flask, render_template, redirect, and url_for from the flask module. We also import LoginManager from the flask_login module.
We create a new instance of the Flask class and set a secret key in the app configuration. The secret key is used to secure session data.
We create an instance of the LoginManager class and initialize it with our Flask app.
Next, we need to create a User class that represents a user in our application.
from flask_login import UserMixin
class User(UserMixin):
def __init__(self, id):
self.id = id
The User class above inherits from UserMixin, which provides default implementations for the methods required by Flask-Login.
Now let’s set up a basic login route that will allow users to log in to our application.
@app.route('/login', methods=['GET', 'POST'])
def login():
user = User(id=1) # In a real application, authenticate the user
login_user(user)
return redirect(url_for('index'))
In the code above, we define a /login route that accepts GET and POST requests. We create a new instance of the User class and log the user in using the login_user function provided by Flask-Login. Finally, we redirect the user to the index route.
Now let’s create a basic logout route that will allow users to log out of our application.
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
In the code above, we define a /logout route that logs the user out using the logout_user function provided by Flask-Login. Finally, we redirect the user to the index route.
Next, we will create a before_request function that will ensure that the user is logged in before accessing certain routes.
@app.before_request
def before_request():
if not current_user.is_authenticated and request.endpoint != 'login':
return redirect(url_for('login'))
In the code above, we define a before_request function that checks if the current user is authenticated and if the endpoint being accessed is not the login route. If the user is not authenticated and the endpoint is not the login route, we redirect the user to the login route.
Finally, let’s create a simple index route that will display a welcome message to authenticated users.
@app.route('/')
def index():
return 'Hello, {}!'.format(current_user.id)
In the code above, we define an index route that displays a welcome message with the current user’s ID.
That’s it! You now have a basic Flask application that implements authentication using Flask-Login. You can expand on this by adding user registration, password hashing, and more advanced authentication features. Flask-Login documentation is a great resource for more information and examples: https://flask-login.readthedocs.io/en/latest/
For people wondering where the code is in this video, you can find it here: https://github.com/arpanneupane19/Python-Flask-Authentication-Tutorial
IF YOU EVER EXPERIENCE ISSUES WITH LOGIN EITHER KEEPING YOU LOGGED IN OR NOT LETTING YOU LOG IN OR JUST MIS-MANAGING THE LOGINS IN ANYWAY:
you only need this line of code once, when running db.create_all()
app.app_context().push()
once you have run db.create_all() you can comment it out.
I dont know why but the user table is not getting created and when i do the .tables i am not getting the user table just blank and next line of sqlite> pls somebody help with this why its happening and how to resolve it
hello i keep having this issue: RuntimeError: Either 'SQLALCHEMY_DATABASE_URI' or 'SQLALCHEMY_BINDS' must be set.
i've checked multiple times and idk whats wrong with my code
3:30 i get an import error
I got struct on the app context. the error was something like use app.app_context() or with app.app_context(): db.create_all(). I had to include app.app_context().push() in the app.py file and also had to use basedir = os.path.abspath(os.path.dirname(__file__)) with app.config['SQLALCHEMY_DATABASE_URI'] =
'sqlite:///' + os.path.join(basedir, 'database.db') in order to get you code to work but I'm good now! thanks man
Goated tutorial
Great video, love that you go step by step and explain why you are adding the code. I know you are using a MAC, but wanted to ask if you tested this full tutorial in a Windows system. It seems that many users are having issues with the DB part of the tutorial and think it might be good for you to provide more insight and answers on the issues that may occur in a Windows environment. When I run 'from app import db', it creates a folder called instance, therefore, when I run db.create_all() I get an error, because there is no database.db in the instance folder.. Can you please try this exact tutorial in Windows and update the video to include the differences? Thank you!
24:03
Thank you
Very good explanation and well presented, thank you. But how about the styling the page
Use minimum font size 20 for youtube this is impossible to see
thanks bro
Wow! Great video! you just saved me a TON of time – new to Flask, and I was busy trying to piece together everything I needed for a simple authentication system, and you nailed it in one! Thanks a ton! I do have a question about some of the items in your requirements.txt – you have some items in there that aren't explicitly called out in the video – cffi, asgiref, dnspython, etc. Can you expand on why you included them?
14:08
from app import app, db
with app.app_context():
db.create_all()
13:59
from flask import Flask, render_template
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import InputRequired, Length
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SECRET_KEY'] = 'thisisasecretkey'
db = SQLAlchemy(app)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
email = db.Column(db.String(150), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
class RegisterForm(FlaskForm):
username = StringField('Username', validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})
password = PasswordField('Password', validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})
submit = SubmitField('Register')
@app.route('/')
def home():
return render_template('home.html')
@app.route('/login')
def login():
return render_template('login.html')
@app.route('/register')
def register():
form = RegisterForm()
return render_template('register.html', form=form)
if _name_ == '__main__':
app.run(debug=True)
15:38
O erro "No module named 'flask'" indica que o módulo Flask não está instalado no seu ambiente Python atual. Para resolver isso, siga os passos abaixo:
### Passos para instalar o Flask
1. *Criar um ambiente virtual* (se ainda não tiver criado):
“`bash
python -m venv venv
“`
2. **Ativar o ambiente virtual**:
– No Windows:
“`bash
venvScriptsactivate
“`
– No macOS/Linux:
“`bash
source venv/bin/activate
“`
3. **Instalar Flask e outras dependências**:
“`bash
pip install flask flask_sqlalchemy flask_login flask_wtf
“`
4. **Verificar a instalação**:
– Você pode verificar se o Flask foi instalado corretamente executando:
“`bash
pip list
“`
– Certifique-se de que `flask`, `flask_sqlalchemy`, `flask_login` e `flask_wtf` estejam listados.
### Reestruturando o projeto
Certifique-se de que a estrutura do seu projeto está correta. Aqui está um exemplo:
“`
my_flask_app/
│
├── app.py
├── models.py
├── forms.py
├── templates/
│ ├── login.html
│ ├── register.html
│ └── home.html
└── static/
└── styles.css
“`
### Arquivo `app.py`
“`python
from flask import Flask, render_template, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from forms import LoginForm, RegisterForm
from models import User, db
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db.init_app(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/')
@app.route('/home')
def home():
return render_template('home.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
return redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return render_template('login.html', form=form)
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
user = User(email=form.email.data, username=form.username.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Your account has been created!', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('home'))
if _name_ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)
“`
### Arquivo `models.py`
“`python
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
db = SQLAlchemy()
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), nullable=False, unique=True)
email = db.Column(db.String(150), nullable=False, unique=True)
password_hash = db.Column(db.String(256), nullable=False)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
“`
### Arquivo `forms.py`
“`python
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
remember = BooleanField('Remember Me')
submit = SubmitField('Login')
class RegisterForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Sign Up')
“`
### Verifique se todos os arquivos estão no mesmo diretório e executando o servidor Flask
Certifique-se de que todos os arquivos estão no diretório correto e execute o servidor Flask novamente. Navegue até o diretório do seu projeto e execute:
“`bash
flask run
“`
Se o Flask ainda não estiver encontrado, tente instalar o Flask explicitamente novamente e garantir que você está ativando o ambiente virtual corretamente:
“`bash
pip install flask
“`
Certifique-se de que o comando `pip list` inclui `flask` na lista de pacotes instalados.
hi im getting this error TypeError: FlaskForm.validate_on_submit() missing 1 required positional argument: 'self' how to resolve it
madan bro random room match epo ???
Say I have 5 web pages but only one of them requires a login. Do I add @login_required only to the route to that page?