flask实现用户注册和登录
通常,无论设计一个什么网页,都会有一个用户管理的功能,这就需要实现用户的注册和登录功能。这里,我们将以一个简单的示例来实现功能完全用户注册和登录的最小demo。
文件路径:
demo
apps
front
__init__.py
views.py
forms.py
models.py
decorators.py
hooks.py
static
...
templates
...
config.py
exts.py
manage.py
server.py
准备
- config.py
import os
# 开启debug模式, 需要在pycharm的Edit Configurations中勾选FLASK_DEBUG
DEBUG = True
# 开启secret_key
SECRET_KEY = os.urandom(24)
# session保存的字段名,可随意设置
FRONT_USER_ID = "front_user_id"
# 配置MySQL数据库
DB_USERNAME = 用户名
DB_PASSWOED = 密码
DB_HOST = "127.0.0.1"
DB_PORT = "3306"
DB_NAME = 数据库名字
DB_URI = "mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8".format(
username=DB_USERNAME, password=DB_PASSWOED, host=DB_HOST, port=DB_PORT, db=DB_NAME
)
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
- exts.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
- manage.py
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from server import create_app
from exts import db
app = create_app()
manager = Manager(app)
Migrate(app, db)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
- server.py
from flask import Flask
import config
from apps.front import bp as front_bp
from exts import db
from flask_wtf import CSRFProtect
def create_app():
app = Flask(__name__)
app.config.from_object(config)
app.register_blueprint(front_bp)
db.init_app(app)
CSRFProtect(app)
return app
if __name__ == '__main__':
app = create_app()
app.run()
- hooks.py
from .views import bp
import config
from flask import session, g, render_template
from .models import FrontUser
@bp.before_request
def before_request():
if config.FRONT_USER_ID in session:
user_id = session.get(config.FRONT_USER_ID)
user = FrontUser.query.get(user_id)
if user:
g.front_user = user
@bp.errorhandler
def page_not_found():
return render_template('front/front_404.html'), 404
用户注册
- 首先,我们要实现一个简单的注册页面
- front_signup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>注册</title>
<link rel="stylesheet" href="{{ url_for('static', filename='layui/css/layui.css') }}">
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.16.0/js/md5.min.js"></script>
</head>
<body>
<div class="sign-box">
<form action="" class="layui-form layui-form-pane sign-form">
<h1>注 册</h1>
<div class="layui-form-item">
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" class="layui-input" lay-verify="required" name="username" placeholder="请输入您的用户名...">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-block">
<input type="password" class="layui-input" lay-verify="required" name="password1" placeholder="请输入您的密码...">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" class="layui-input" lay-verify="required" name="password2" placeholder="请再次却惹您的密码...">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="signup">立即注册</button>
</div>
</div>
<div class="layui-form-item">
已注册 <a href="{{ url_for('front.signin') }}" style="color: #0000FF">我要登录</a>
</div>
</form>
</div>
<script src="{{ url_for('static', filename='layui/layui.js') }}"></script>
<script>
layui.use(['form'], function () {
var form = layui.form;
// 监听提交
form.on('submit(signup)', function (data) {
// data.field 为表单数据,以 key: value 的形式展现
console.log(data.field);
var username= data.field.username;
var password1 = data.field.password1;
var password2 = data.field.password2;
$.ajax({
'method': 'post',
'url': '/signup/',
'data': {
'username': username,
'password1': password1,
'password2': password2,
},
'success': function (data) {
if(data['code'] === 200) {
window.location = '/';
} else {
alert(data['message']);
}
},
'fail': function (error) {
alert("网络出错了...");
}
});
return false;
// layer.msg(JSON.stringify(data.field));
// return false;
})
})
</script>
</body>
</html>
- 实现对应的表单form来接收前端的数据
- forms.py
from wtforms import StringField
from wtforms.validators import Regexp, EqualTo, InputRequired
class SignupForm(Form):
username = StringField(validators=[InputRequired(message="请输入您的用户名!")])
password1 = StringField(validators=[Regexp(r"[0-9a-zA-Z_\.]{6,20}", message="请输入正确格式的密码!")])
password2 = StringField(validators=[EqualTo("password1", message="两次输入的密码不一致!")])
def get_error(self):
message = self.errors.popitem()[1][0]
return message
- 实现对应的模型model
- models.py
from exts import db
import shortuuid
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
class FrontUser(db.Model):
__tablename__ = "frontuser"
id = db.Column(db.String(100), primary_key=True, default=shortuuid.uuid)
username = db.Column(db.String(100), nullable=False)
_password = db.Column(db.String(100), nullable=False)
join_time = db.Column(db.DateTime, default=datetime.now)
def __init__(self, *args, **kwargs):
if "password" in kwargs:
self.password = kwargs.get("password")
kwargs.pop("password")
super(FrontUser, self).__init__(*args, **kwargs)
@property
def password(self):
return self._password
@password.setter
def password(self, newpwd):
self._password = generate_password_hash(newpwd)
def check_password(self, rawpwd):
return check_password_hash(self._password, rawpwd)
- 实现对应的视图
- views.py
from flask import Blueprint, render_template, views, request, session, g, jsonify
from apps.front.forms import SignupForm, SigninForm
from apps.front.models import EnterpriseNode
from .decorators import login_required
from exts import db
import config
bp = Blueprint("front", __name__)
@bp.route('/')
@login_required
def index():
return render_template('front/front_index.html')
class SignupView(views.MethodView):
def get(self):
return render_template('front/front_signup.html')
def post(self):
form = SignupForm(request.form)
if form.validate():
username = form.username.data
password = form.password1.data
user = FrontUser(
username=username,
password=password,
)
db.session.add(user)
db.session.commit()
return jsonify({'code': 200, 'message': '注册成功', 'data': None)
else:
print(form.get_error())
return jsonify({'code': 400, 'message'=form.get_error(), 'data': None)
bp.add_url_rule('/signup/', view_func=SignupView.as_view('signup'))
到这里,用户的注册功能就实现了
登录功能
这里只给出
views.py
的代码,其他的可以参考注册功能的实现
class SigninView(views.MethodView):
def get(self):
return render_template('front/front_signin.html')
def post(self):
form = SigninForm(request.form)
if form.validate():
username = form.enterprise.data
password = form.password.data
remember = form.remember.data
user = FrontUser.query.filter_by(username=username).first()
# 验证是否存在用户和密码
if user and user.check_password(password):
session[config.FRONT_USER_ID] = user.id # 保存session信息,维持登录
g.front_user = user # 保存到g参数,用于实现登录校验,亦可再html模板中使用
if remember:
session.permanent = True
return jsonify({'code': 200, 'message': '登录成功', 'data': None})
else:
return jsonify({'code': 400, 'message': "用户名或密码错误!", 'data': None})
else:
return jsonify({'code': 400, 'message': form.get_error(), 'data': None})