Browse Source

Chapter 8: Login and logout with Flask-Login (8c)

master
T. Meissner 6 years ago
parent
commit
115d1e1da1
10 changed files with 95 additions and 37 deletions
  1. +6
    -0
      app/__init__.py
  2. +11
    -0
      app/auth/forms.py
  3. +24
    -3
      app/auth/views.py
  4. +2
    -24
      app/main/views.py
  5. +9
    -2
      app/models.py
  6. +4
    -0
      app/templates/auth/login.html
  7. +7
    -0
      app/templates/base.html
  8. +1
    -8
      app/templates/index.html
  9. +30
    -0
      migrations/versions/655013143dbb_.py
  10. +1
    -0
      requirements.txt

+ 6
- 0
app/__init__.py View File

@ -3,6 +3,7 @@ from flask_bootstrap import Bootstrap
from flask_mail import Mail from flask_mail import Mail
from flask_moment import Moment from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import config from config import config
@ -12,6 +13,10 @@ moment = Moment()
db = SQLAlchemy() db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
def create_app(config_name): def create_app(config_name):
app = Flask(__name__) app = Flask(__name__)
app.config.from_object(config[config_name]) app.config.from_object(config[config_name])
@ -21,6 +26,7 @@ def create_app(config_name):
mail.init_app(app) mail.init_app(app)
moment.init_app(app) moment.init_app(app)
db.init_app(app) db.init_app(app)
login_manager.init_app(app)
from .main import main as main_blueprint from .main import main as main_blueprint
app.register_blueprint(main_blueprint) app.register_blueprint(main_blueprint)


+ 11
- 0
app/auth/forms.py View File

@ -0,0 +1,11 @@
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, Email
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Length(1, 64),
Email()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Keep me logged in')
submit = SubmitField('Log in')

+ 24
- 3
app/auth/views.py View File

@ -1,7 +1,28 @@
from flask import render_template
from flask import render_template, redirect, request, url_for, flash
from flask_login import login_user, logout_user, login_required
from . import auth from . import auth
from ..models import User
from .forms import LoginForm
@auth.route('/login')
@auth.route('/login', methods=['GET', 'POST'])
def login(): def login():
return render_template('auth/login.html')
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user is not None and user.verify_password(form.password.data):
login_user(user, form.remember_me.data)
next = request.args.get('next')
if next is None or not next.startswith('/'):
next = url_for('main.index')
return redirect(next)
flash('Invalid username or password')
return render_template('auth/login.html', form=form)
@auth.route('/logout')
@login_required
def logout():
logout_user()
flash('You have been logged out.')
return redirect(url_for('main.index'))

+ 2
- 24
app/main/views.py View File

@ -1,29 +1,7 @@
from flask import render_template, session, redirect, url_for, current_app
from .. import db
from ..models import User
from ..email import send_email
from flask import render_template
from . import main from . import main
from .forms import NameForm
@main.route('/', methods=['GET', 'POST']) @main.route('/', methods=['GET', 'POST'])
def index(): def index():
form = NameForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.name.data).first()
if user is None:
user = User(username=form.name.data)
db.session.add(user)
db.session.commit()
session['known'] = False
if current_app.config['FLASKY_ADMIN']:
send_email(current_app.config['FLASKY_ADMIN'], 'New user',
'mail/new_user', user=user)
else:
session['known'] = True
session['name'] = form.name.data
form.name.data = ''
return redirect(url_for('.index'))
return render_template('index.html',
form=form, name=session.get('name'),
known=session.get('known', False))
return render_template('index.html')

+ 9
- 2
app/models.py View File

@ -1,5 +1,6 @@
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from . import db
from flask_login import UserMixin
from . import db, login_manager
class Role(db.Model): class Role(db.Model):
@ -12,9 +13,10 @@ class Role(db.Model):
return '<Role %r>' % self.name return '<Role %r>' % self.name
class User(db.Model):
class User(UserMixin, db.Model):
__tablename__ = 'users' __tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(64), unique=True, index=True)
username = db.Column(db.String(64), unique=True, index=True) username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128)) password_hash = db.Column(db.String(128))
@ -32,3 +34,8 @@ class User(db.Model):
def __repr__(self): def __repr__(self):
return '<User %r>' % self.username return '<User %r>' % self.username
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))

+ 4
- 0
app/templates/auth/login.html View File

@ -1,4 +1,5 @@
{% extends "base.html" %} {% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky - Login{% endblock %} {% block title %}Flasky - Login{% endblock %}
@ -6,4 +7,7 @@
<div class="page-header"> <div class="page-header">
<h1>Login</h1> <h1>Login</h1>
</div> </div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %} {% endblock %}

+ 7
- 0
app/templates/base.html View File

@ -25,6 +25,13 @@
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="{{ url_for('main.index') }}">Home</a></li> <li><a href="{{ url_for('main.index') }}">Home</a></li>
</ul> </ul>
<ul class="nav navbar-nav navbar-right">
{% if current_user.is_authenticated %}
<li><a href="{{ url_for('auth.logout') }}">Log out</a></li>
{% else %}
<li><a href="{{ url_for('auth.login') }}">Log in</a></li>
{% endif %}
</ul>
</div> </div>
</div> </div>
</div> </div>


+ 1
- 8
app/templates/index.html View File

@ -1,16 +1,9 @@
{% extends "base.html" %} {% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %} {% block title %}Flasky{% endblock %}
{% block page_content %} {% block page_content %}
<div class="page-header"> <div class="page-header">
<h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
{% if not known %}
<p>Pleased to meet you!</p>
{% else %}
<p>Happy to see you again!</p>
{% endif %}
<h1>Hello, {% if current_user.is_authenticated %}{{ current_user.username }}{% else %}Stranger{% endif %}!</h1>
</div> </div>
{{ wtf.quick_form(form) }}
{% endblock %} {% endblock %}

+ 30
- 0
migrations/versions/655013143dbb_.py View File

@ -0,0 +1,30 @@
"""empty message
Revision ID: 655013143dbb
Revises: e7148b675688
Create Date: 2018-11-01 23:41:21.492859
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '655013143dbb'
down_revision = 'e7148b675688'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('users', sa.Column('email', sa.String(length=64), nullable=True))
op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_users_email'), table_name='users')
op.drop_column('users', 'email')
# ### end Alembic commands ###

+ 1
- 0
requirements.txt View File

@ -4,6 +4,7 @@ Click==7.0
dominate==2.3.4 dominate==2.3.4
Flask==1.0.2 Flask==1.0.2
Flask-Bootstrap==3.3.7.1 Flask-Bootstrap==3.3.7.1
Flask-Login==0.4.1
Flask-Mail==0.9.1 Flask-Mail==0.9.1
Flask-Migrate==2.2.1 Flask-Migrate==2.2.1
Flask-Moment==0.6.0 Flask-Moment==0.6.0


Loading…
Cancel
Save