一. 安装flask-login扩展
&pip install flask-login
安装完新的扩展以后不要忘记更新requirements.txt文件:
&pip freeze >requirements.txt
二. 初始化扩展——|-app/__init__.py:
from flask_login import LoginManager
login_manager = LoginManager() #创建实例
login_manager.session_protection = 'strong' #该参数有三个选项:None,'basic', 'strong', 保护用户会话不被窃取
login_manager.login_view = 'auth.login' #记录登录视图
def create_app(config_name):
#...
login_manager.init_app(app) #初始化
return app
三. 修改|-app/models.py
flask_login要求实现下面四个用户方法;flask-login还要求程序实现一个回调函数, 根据用户id加载用户。
方法 | 说明 |
is_authenticated | 如果用户已经登录, 返回True |
is_active | 如果允许用户登录, 必须返回True;如果禁用账户,可以返回False |
is_anonymous | 对普通用户必须返回False |
get_id() | 必须返回用户的唯一标志符 |
我们可以自己在User类中实现这四个方法, 还有一更简便的做法是, 让User类继承UserMixin, 因为UserMixin已经实现了这四个方法:
from flask import UserMixin
from . import db, login_manager
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
password_hash = db.Column(db.String(128))
email = db.Column(db.String(64), unique=True, index=True) #为了便于登录, 我们增加了email字段, 对用户来说email地址比用户名更容易记住。
#flask-login要求程序实现一个回调函数, 根据用户id加载用户:
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
四. 修改|-app/auth/forms.py
该脚本定义登录表单:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import Length, Email, DataRequired
class LoginForm(FlaskForm):
email = StringField('email', validators=[ Length(1, 64), Email() ])
password = PasswordField('password', validators=[ DataRequired() ])
remember_me = BooleanField('keep me log in')
submit = SubmitField('log_in')
五. 修改|-app/-auth/-views.py
from . import auth
from .forms import LoginForm
from ..models import User
from flask_login import login_user, login_required, logout_user
from flask import redirect, request, url_for, flash, render_template
@auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit(): #表单数据通过字段的验证函数
user = User.query.filter_by(email=form.email.data).first() #从数据库中查询有无该email的用户
if user and user.verify_password(form.password.data): #用户存在且密码正确
login_user(user, form.remember_me.data) #登录用户, 第二个参数是记住登录状态
#重定向, or前面的值是上个浏览页面(ps:登录页面)的url, 如果用户访问未授权的url就会重定向到登录页面, 否 #则返回主页。
return redirect(request.args.get('next') or url_for('main.index'))
flash('Invalid email or password!') #如果用户不存在或者密码不正确刷新flash消息
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'))
六. 修改|-app/-templates
1.base.html #在导航条增加一login和logout链接
<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>
current_user是flask-login提供的, 可以直接在视图函数和模板中使用, 如果当前用户已登录就显示Log Out, 否则显示Log In。
2. index.html
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {% if current_user.is_authenticated() %} {{ current_user.username }} {% else %}Stranger{% endif %}!</h1>
<p>{% if known%}happy to see you again{% else %}nice to meet you{% endif %}</p>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}
3.auth/login.html
{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block title %}Flasky - Login{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Login</h1>
</div>
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
七. 效果演示
1. 创建一个用户, 以备测试:
&python manage.py shell
>u = User(email='1546879589@qq.com', username='john', password='cat')
>db.session.add(u)
>db.session.commit()