Flask 系列之 LoginManager
程序员文章站
2022-12-28 15:08:22
说明 操作系统:Windows 10 Python 版本:3.7x 虚拟环境管理器:virtualenv 代码编辑器:VS Code 实验目标 通过使用 flask login 进行会话管理的相关操作,并完成用户合法性登陆和退出。 安装 使用 首先,在 中创建 login_manager ,并进行相 ......
说明
- 操作系统:windows 10
- python 版本:3.7x
- 虚拟环境管理器:virtualenv
- 代码编辑器:vs code
实验目标
通过使用 flask-login 进行会话管理的相关操作,并完成用户合法性登陆和退出。
安装
pip install flask-login
使用
首先,在 todlist\app\__init__.py
中创建 login_manager,并进行相关配置,示例代码如下所示:
from flask import flask from flask_sqlalchemy import sqlalchemy from flask_bootstrap import bootstrap from flask_login import loginmanager from config import config app = flask(__name__) app.config.from_object(config) db = sqlalchemy(app) bootstrap = bootstrap(app) login_manager = loginmanager(app) login_manager.login_view = 'login' login_manager.login_message = '你必须登陆后才能访问该页面' login_manager.login_message_category = "info" from app import views
然后,完善我们 todolist\models.py
中关于用户密码校验部分的逻辑处理,示例代码如下所示:
from app import db, login_manager from datetime import datetime from werkzeug.security import check_password_hash, generate_password_hash from flask_login import usermixin, login_user @login_manager.user_loader def load_user(user_id): user = user.query.get(user_id) return user class user(db.model, usermixin): __tablename__ = 'users' # __table_args__ = {"useexisting": true} id = db.column(db.integer, primary_key=true) name = db.column(db.string(20), nullable=false, unique=true) email = db.column(db.string(120), nullable=false, unique=true) pwd = db.column(db.string(120), nullable=false) things = db.relationship('thing', backref='user', lazy='dynamic') def __repr__(self): return "<user %r>" % self.name def generate_password_hash(self, pwd): self.pwd = generate_password_hash(pwd) def check_password_hash(self, pwd): return check_password_hash(self.pwd, pwd) class thing(db.model): __tablename__ = 'things' # __table_args__ = {"useexisting": true} id = db.column(db.integer, primary_key=true) user_id = db.column(db.integer, db.foreignkey('users.id')) title = db.column(db.string(20), nullable=false) text = db.column(db.text, nullable=false) add_date = db.column(db.datetime, default=datetime.now) def __repr__(self): return "<todo %r>" % self.id
然后在 todolist\forms.py
中添加一个用于处理用户登陆的表单提交类,示例代码如下所示:
from flask_wtf import flaskform from wtforms import stringfield, submitfield, textareafield, passwordfield from wtforms.validators import datarequired, length, email, equalto, validationerror from models import user class registerform(flaskform): username = stringfield('用户名:', validators=[ datarequired(), length(min=6, max=20)]) email = stringfield('邮箱:', validators=[datarequired(), email()]) pwd = passwordfield('密码:', validators=[ datarequired(), length(min=8, max=120)]) confirm = passwordfield('确认密码:', validators=[ datarequired(), equalto('pwd')]) submit = submitfield('提交') def validate_username(self, username): user = user.query.filter_by(name=username.data).first() if user: raise validationerror("用户昵称已存在。") def validate_email(self, email): user = user.query.filter_by(email=email.data).first() if user: raise validationerror('邮箱已存在.') class loginform(flaskform): username = stringfield('用户名:', validators=[ datarequired(), length(min=6, max=20)]) password = passwordfield('密码:', validators=[datarequired()]) submit = submitfield('登陆') def validate_username(self, username): user = user.query.filter_by(name=username.data) if not user: raise validationerror('用户名不存在。')
然后修改我们的 todolist\app\views.py
,添加用户登陆和登出的路由处理函数,示例代码如下所示:
from flask import render_template, redirect, url_for, flash from flask_login import login_user, login_required, current_user, logout_user from app import app, db from forms import registerform, loginform from models import user @app.context_processor def inject_user(): user = user.query.first() return dict(user=user) @app.route('/') @app.route('/index') def index(): if not current_user.is_authenticated: return redirect(url_for('login')) return render_template('index.html', title="首页") @app.route('/login', methods=['post', 'get']) def login(): form = loginform() if form.validate_on_submit(): name = form.username.data pwd = form.password.data user = user.query.filter_by(name=name).first() if user and user.check_password_hash(pwd): login_user(user) flash('登陆成功。', category='info') return redirect(url_for('index')) else: flash("密码或账户错误。", category='error') return render_template('login.html', title='登录', form=form) @app.route('/logout') @login_required def logout(): logout_user() flash('再见!') return redirect(url_for('login')) @app.route('/register', methods=['post', 'get']) def register(): form = registerform() if form.validate_on_submit(): username = form.username.data email = form.email.data pwd = form.pwd.data user = user(name=username, email=email) user.generate_password_hash(pwd) db.session.add(user) db.session.commit() flash('注册成功', category='info') return redirect(url_for('login')) return render_template('register.html', title='注册', form=form)
接着,修改我们 todolist\app\templates\login.html
页面,添加用户登陆的表单,示例代码如下所示:
{% extends 'base.html' %} {% block content %} <h1>登录页面</h1> {% from 'bootstrap/form.html' import render_form %} {{ render_form(form) }} {% endblock %}
修改我们的 todolist\app\templates\nav.html
页面,完善菜单栏的逻辑控制,示例代码如下所示:
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class="container"> <a class="navbar-brand" href="#">愿望清单</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsupportedcontent" aria-controls="navbarsupportedcontent" aria-expanded="false" aria-label="toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarsupportedcontent"> <ul class="navbar-nav mr-auto"> <li class="nav-item {% if request.endpoint == 'index' %} active {% endif %}"> <a class="nav-link" href="{{ url_for('index') }}">首页<span class="sr-only">(current)</span></a> </li> </ul> <ul class="navbar-nav"> {% if current_user.is_authenticated and user %} <li class="nav-item {% if request.endpoint == 'logout' %} active {% endif %}"> <a class="nav-link" href="{{ url_for('logout') }}">登出</a> </li> {% else %} <li class="nav-item {% if request.endpoint == 'login' %} active {% endif %}"> <a class="nav-link" href="{{ url_for('login') }}">登录</a> </li> <li class="nav-item {% if request.endpoint == 'register' %} active {% endif %}"> <a class="nav-link" href="{{ url_for('register') }}">注册</a> </li> {% endif %} </ul> </div> </div> </nav>
修改我们的 todolist\app\templates\index.html
页面,显示当前登陆的用户,示例代码如下所示:
{% extends 'base.html' %} {% block content %} {% if current_user.is_authenticated and user %} <h1>{{ current_user.name }},欢迎回来</h1> {% else %} <h1>首页</h1> {% endif %} {% endblock %}
此时,当我们运行起我们的网站后进入注册页面 http://127.0.0.1:5000 就可以进行用户的注册、登陆和登出了。
参考连接
推荐阅读
-
spring-boot-2.0.3不一样系列之源码篇 - run方法(三)之createApplicationContext,绝对有值得你看的地方
-
Javascript数组系列三之迭代方法2
-
【JavaScript系列】你应掌握的JavaScript之函数(一)
-
死磕 java同步系列之终结篇
-
详解Spring Data JPA系列之投影(Projection)的用法
-
怀孕系列之月经推迟几天可以验孕?
-
ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程
-
PHP字符串函数系列之nl2br(),在字符串中的每个新行 ( ) 之前插入 HTML 换行符br
-
死磕 java同步系列之Phaser源码解析
-
WPF之图片处理系列