
Flask
账户注册
综合使用所学习过的知识,搭建登录页面
代码示例:
https://github.com/ningwenyan/demo_code/tree/master/flask_demo_code/T26
总览
❯ tree
.
├── app.py
├── auth
│ ├── auth_form.py
│ ├── __init__.py
│ └── views.py
├── common
│ ├── errors.py
│ ├── exts.py
│ ├── __init__.py
│ ├── mailModel.py
│ └── sqlModel.py
├── config.py
├── manager.py
├── migrations
│ ├── alembic.ini
│ ├── env.py
│ ├── README
│ ├── script.py.mako
│ └── versions
│ ├── 44bc21866b0d_.py
│ └── __pycache__
│ └── 44bc21866b0d_.cpython-37.pyc
├── static
└── templates
├── 401.html
├── 403.html
├── 404.html
├── 500.html
└── auth
├── change_email.html
├── change_password.html
├── index.html
├── login.html
│ ├── change_email.html
│ ├── change_email.txt
│ ├── confirm.html
│ ├── confirm.txt
│ ├── password_reset.html
│ └── password_reset.txt
├── main
│ └── reset_password.html
├── personal.html
├── register.html
└── reset_password.html
设计数据库(加密密码)
简单的来说,这里只设计一个用户的一些基本属性,需要注意的是,用户的密码需要在数据库中加密,避免用户密码泄露.
# config.py
# 设置数据库的基本信息
# 数据库连接
DB_URI = 'mysql+pymysql://root:2008.Cn123@192.168.0.101:3306/flask_login_demo1' # 确保数据库存在
# 指定数据库连接
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False# common/exts.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()# app.py
from common.exts import db
db.init_app(app)# common/sqlModel.py
from flask_login import UserMixin
from .exts import db, flask_bcrypt
class User(db.Model, UserMixin):
__tablename__ = 'users'
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)
_password_hash = db.Column(db.String(128)) # 隐藏属性值,不能被外部访问
confirmed = db.Column(db.Boolean, default=False) # flag, 标识是否注册激活
# 密码加密
# 使用_password作为类属性,这是私有属性,不允许访问
# 映射一个password方法
def __init__(self, email, username, password, **kwargs):
self.email = email
self.username = username
self.password = password
@property
def password(self):
return self._password_hash
@password.setter
def password(self, raw_password):
# 加密密码
self._password_hash = flask_bcrypt.generate_password_hash(raw_password)
@password.deleter
def password(self):
del self._password_hash
# 定义解密密码
def check_password(self, password):
# 如果原始密码和加密后的密码相同,返回True
return flask_bcrypt.check_password_hash(self._password_hash, password)
表单自验证用户
设计完数据库映射后,需要考虑一个问题,就是注册的重复性问题.一个邮箱只能注册一次,一个用户名有且只能存在一个.
# auth/auth_form.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, ValidationError
from wtforms.validators import Length, EqualTo, Regexp, Required, DataRequired, Email
from common.sqlModel import User
class LoginForm(FlaskForm):
email = StringField(validators=[Email(), DataRequired(), Length(1, 64)])
password = PasswordField(validators=[Length(1, 24)])
confirmed = BooleanField()
class RegisterForm(FlaskForm):
email = StringField('Email', validators=[Email(), Length(1, 64), DataRequired()])
username = StringField('Username', validators=[
DataRequired(), Length(1, 64),
Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0,
'Username must have only letters, numbers, dots or '
'underscores')
])
password = PasswordField('Password', validators=[Length(1, 24), Required()])
con_password = PasswordField('Confirm Password', validators=[EqualTo('password')])
# 自定义Field,验证邮箱和用户
def validate_email(self, field):
if User.query.filter_by(email = field.data.lower()).first():
raise ValidationError('Email already registered.')
def validate_username(self, filed):
if User.query.filter_by(username = filed.data).first():
raise ValidationError('Username already in use.')
定义视图函数
定义注册和登录网站的视图函数
#!/usr/bin/env python
# coding=utf-8
from . import auth_bp
from flask import render_template, redirect, url_for, request, flash
from .auth_form import LoginForm, RegisterForm
from common.exts import db
from common.sqlModel import User
from flask_login import login_user, login_required, current_user
@auth_bp.route('/')
def index():
return render_template('auth/index.html')
# 设计注册,登录页面
@auth_bp.route('/register/', methods = ['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
"""注册账户"""
email = form.email.data.lower()
username = form.username.data
password = form.password.data
user = User(email, username, password)
db.session.add(user)
db.session.commit()
return redirect(url_for('auth.login'))
return render_template('auth/register.html')
@auth_bp.route('/login/', methods = ['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
"""登录用户"""
email = form.email.data.lower()
password = form.password.data
user = User.query.filter_by(email=email).first()
# 数据库中有账户,并且能够验证密码
if user is not None and user.check_password(password):
login_user(user)
# 判断 next
next = request.args.get('next')
if next is None or not next.startswitch('/'):
next = redirect(url_for('auth.index'))
return redirect(url_for(next or 'auth.personal'))
else:
flash('无效的邮箱或密码.')
return render_template('auth/login.html')
# 限制登录用户访问 login_required
@auth_bp.route('/personal/')
@login_required
def personal():
return render_template('auth/personal.html', user = current_user)
@auth_bp.route('/logout/')
@login_required
def logout():
return redirect(url_for('auth.index'))使用
flash
返回消息后,需要在前端添加反馈<!----login.html------>
<form action="" method="post">
{# 解决csrf_token #}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<div>
<label for="">Email:</label>
<input type="text" placeholder="Email" name="email">
</div>
<div>
<label for="">Password:</label>
<input type="password" placeholder="Password" name="password">
</div>
<div>
<label for="">Remember me:</label>
<input type="checkbox" name="remember">
</div>
<div>
<input type="submit" name="submit" value="Login">
</div>
{# 接受后端返回的flash消息 #}
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
{{ message }}
{% endfor %}
{% endif %}
{% endwith %}
</form>
定义Flask Login
回调函数
# sqlModel.py
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
定义CSRF
保护
我们使用了
Flask Form
表单验证,所以这里要进行CSRF
保护# exts.py
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_bcrypt import Bcrypt
from flask_wtf.csrf import CSRFProtect
db = SQLAlchemy()
login_manager = LoginManager()
flask_bcrypt = Bcrypt()
csrf = CSRFProtect()# app.py
from common.exts import db, login_manager, flask_bcrypt, csrf
csrf.init_app(app)# config.py
import os
# CSRF SECRET_KEY
SECRET_KEY = os.urandom(12)对所有使用
POST
表单的页面添加保护{# 解决csrf_token #}
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
指定Flask Login
登录路由
# app.py
# 指定登录的URL
login_manager.login_view = 'auth.login'
– END –
原文始发于微信公众号(Flask学习笔记):Flask账户注册(2)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/36408.html