提交 65e72ce0 编写于 作者: C Corley

V1.3

上级 40ff2bc7
......@@ -9,4 +9,10 @@
在V1.0的基础上进一步实现CMS用户登录、错误信息返回、登录限制和CSRF保护、CMS用户名渲染和注销、CMS个人页面和模板抽离等功能,进一步丰富后台管理功能。
#### V1.2
在V1.1的基础上实现后台修改密码布局、通过Ajax实现局部更新修改密码、优化Json数据返回、sweetalert美化提示框、修改邮箱界面搭建功能。
\ No newline at end of file
在V1.1的基础上实现后台修改密码布局、通过Ajax实现局部更新修改密码、优化Json数据返回、sweetalert美化提示框、修改邮箱界面搭建功能。
#### V1.3
在V1.2的时候进一步完善,首先实现在Flask中发送邮件,并进一步定义发送验证码,并进一步实现修改邮箱,还对权限和角色模型进行了定义。
注意:
在配置文件config.md中需要将自己的邮箱信息输入,才能正常实现其功能。
\ No newline at end of file
from wtforms import Form, StringField, IntegerField
from wtforms import Form, StringField, IntegerField, ValidationError
from wtforms.validators import Email, InputRequired, Length, EqualTo
from utils import clcache
class BaseForm(Form):
......@@ -17,4 +18,16 @@ class LoginForm(BaseForm):
class ResetPwdForm(BaseForm):
oldpwd = StringField(validators=[Length(6, 20, message='密码长度应介于6-20')])
newpwd = StringField(validators=[Length(6, 20, message='密码长度应介于6-20')])
newpwd2 = StringField(validators=[EqualTo("newpwd", message='两次输入密码不一致')])
\ No newline at end of file
newpwd2 = StringField(validators=[EqualTo("newpwd", message='两次输入密码不一致')])
class ResetEmailForm(BaseForm):
email = StringField(validators=[Email(message='您的邮箱格式有误,请重新输入')])
captcha = StringField(validators=[Length(4, 4, message='请输入4位验证码')])
def validate_captcha(self, form):
captcha = self.captcha.data
email = self.email.data
redis_captcha = clcache.get_captcha(email)
if not redis_captcha or captcha.lower() != redis_captcha.lower():
raise ValidationError('邮箱验证码错误')
\ No newline at end of file
......@@ -30,4 +30,47 @@ class CMSUser(db.Model):
def check_password(self, raw_password):
'''验证密码是否正确'''
result = check_password_hash(self.password, raw_password)
return result
\ No newline at end of file
return result
class CMSPermission(object):
# 255二进制表示所有权限
ALL_PERMISSION = 0b11111111
# 访问权限
VISITOR = 0b00000001
# 管理帖子权限
POSTER = 0b00000010
# 管理评论权限
COMMENTER = 0b00000100
# 管理板块
BOARDER = 0b00001000
# 管理前台用户
FRONTUSER = 0b00010000
# 管理前台用户
CMSUSER = 0b00100000
# 管理前台用户
ADMINER = 0b01000000
cms_role_user = db.Table(
'cms_role_user',
db.Column('cms_role_id', db.Integer, db.ForeignKey('cms_role.id'), primary_key=True),
db.Column('cms_user_id', db.Integer, db.ForeignKey('cms_user.id'), primary_key=True)
)
class CMSRole(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.String(50), nullable=False)
desc = db.Column(db.String(200), nullable=False)
create_time = db.Column(db.DateTime, default=datetime.now())
permissions = db.Column(db.Integer, default=CMSPermission.VISITOR)
users = db.relationship('CMSUser', secondary=cms_role_user, backref='roles')
\ No newline at end of file
from flask import Blueprint, render_template, views, request, redirect, url_for, session, g
from apps.cms.forms import LoginForm, ResetPwdForm
from flask_mail import Message
from apps.cms.forms import LoginForm, ResetPwdForm, ResetEmailForm
from apps.cms.models import CMSUser
from exts import db
from utils import restful
from exts import db, mail
from utils import restful, random_captcha, clcache
# from .decorators import login_required # .代表当前路径
......@@ -87,9 +88,35 @@ class ResetEmailView(views.MethodView):
return render_template('cms/cms_resetemail.html')
def post(self):
pass
form = ResetEmailForm(request.form)
if form.validate():
email = form.email.data
# 修改用户邮箱
g.cms_user.email = email
db.session.commit()
return restful.success()
else:
return restful.params_error(form.get_error())
class EmailCaptchaView(views.MethodView):
def get(self):
email = request.args.get('email')
if not email:
return restful.params_error('请传递邮箱参数')
# 发送邮件验证码,可以是4位或6位的数字与英文组合
captcha = random_captcha.get_random_captcha(4)
try:
message = Message('熊熊论坛验证码', recipients=[email], body='您正在进行更改邮箱验证,验证码是%s,5分钟内有效,请及时输入、注意保密。' % captcha)
mail.send(message)
except Exception as e:
print(e.args[0])
return restful.server_error('邮件发送异常,请检查重试')
clcache.save_captcha(email, captcha)
return restful.success(message='邮件发送成功,请注意接收验证码')
cms_bp.add_url_rule('/login/', view_func=LoginView.as_view('login'))
cms_bp.add_url_rule('/resetpwd/', view_func=ResetPwdView.as_view('resetpwd'))
cms_bp.add_url_rule('/resetemail/', view_func=ResetEmailView.as_view('resetemail'))
cms_bp.add_url_rule('/email_captcha/', view_func=EmailCaptchaView.as_view('email_captcha'))
......@@ -6,7 +6,7 @@
from flask import Flask
from flask_wtf import CSRFProtect
from exts import db
from exts import db, mail
from apps.cms.views import cms_bp
from apps.front.views import front_bp
import config
......@@ -15,8 +15,8 @@ import config
app = Flask(__name__)
CSRFProtect(app)
app.config.from_object(config)
app.config['TEMPLATE_AUTO_RELOAD'] = True
db.init_app(app)
mail.init_app(app)
app.register_blueprint(cms_bp)
app.register_blueprint(front_bp)
......
......@@ -8,10 +8,24 @@ PASSWORD = 'root'
DATABASE = 'flask_bbs'
DB_URL = 'mysql+mysqlconnector://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
TEMPLATE_AUTO_RELOAD = True
SQLALCHEMY_DATABASE_URI = DB_URL
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_POOL_RECYCLE = 280
SQLALCHEMY_POOL_SIZE = 20
# 设置密钥
SECRET_KEY = os.urandom(15)
\ No newline at end of file
SECRET_KEY = os.urandom(15)
# 发送邮箱服务地址
MAIL_SERVER = 'smtp.qq.com'
# 邮箱端口,为587或465,为587时TLS设置为True,为465时SSL设置为True
MAIL_PORT = 587
MAIL_USE_TLS = True
# MAIL_USE_SSL = True # MAIL_PORT为465时设置此项
# 用户名可以为你的邮箱,需要自行添加
MAIL_USERNAME = '123456789@qq.com'
# 邮箱密码,不是邮箱账号密码,而是第三方客户端登录使用的授权码,需要自行获取
MAIL_PASSWORD = 'xxxxxxxxxxxxxxxx'
# 发送者即你的邮箱,需要自行添加
MAIL_DEFAULT_SENDER = '123456789@qq.com'
\ No newline at end of file
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail
db = SQLAlchemy()
\ No newline at end of file
db = SQLAlchemy()
mail = Mail()
\ No newline at end of file
......@@ -2,7 +2,7 @@ from flask_script import Manager
from bbs import app
from flask_migrate import Migrate, MigrateCommand
from exts import db
from apps.cms.models import CMSUser
from apps.cms.models import CMSUser, CMSRole
manager = Manager(app)
Migrate(app, db)
......
"""empty message
Revision ID: ba80d307aa21
Revises: f7a47bdbaa71
Create Date: 2020-06-05 20:35:29.305779
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ba80d307aa21'
down_revision = 'f7a47bdbaa71'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('cms_role',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=50), nullable=False),
sa.Column('desc', sa.String(length=200), nullable=False),
sa.Column('create_time', sa.DateTime(), nullable=True),
sa.Column('permissions', sa.Integer(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_table('cms_role_user',
sa.Column('cms_role_id', sa.Integer(), nullable=False),
sa.Column('cms_user_id', sa.Integer(), nullable=False),
sa.ForeignKeyConstraint(['cms_role_id'], ['cms_role.id'], ),
sa.ForeignKeyConstraint(['cms_user_id'], ['cms_user.id'], ),
sa.PrimaryKeyConstraint('cms_role_id', 'cms_user_id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('cms_role_user')
op.drop_table('cms_role')
# ### end Alembic commands ###
......@@ -23,6 +23,7 @@ PyMySQL==0.9.3
python-dateutil==2.8.1
python-editor==1.0.4
pytz==2020.1
redis==3.5.3
six==1.14.0
SQLAlchemy==1.3.16
Werkzeug==1.0.1
......
......@@ -195,4 +195,8 @@ body {
border-radius: 2px;
background: #ecedf0;
overflow: hidden;
}
.form-container {
width: 300px;
}
\ No newline at end of file
var lgajax = {
var clajax = {
'get': function (args) {
args['method'] = 'get';
this.ajax(args);
......@@ -28,10 +28,10 @@ $(function () {
event.preventDefault();
var email = $("input[name='email']").val();
if (!email) {
lgalert.alertInfoToast('请输入邮箱');
clalert.alertInfoToast('请输入邮箱');
return;
}
var lgajax = {
var clajax = {
'get': function (args) {
args['method'] = 'get';
this.ajax(args);
......@@ -56,20 +56,20 @@ $(function () {
});
}
};
lgajax.get({
clajax.get({
'url': '/cms/email_captcha/',
'data': {
'email': email
},
'success': function (data) {
if (data['code'] == 200) {
lgalert.alertSuccessToast('邮件发送成功!请注意查收!');
if (data['code'] === 200) {
clalert.alertSuccessToast('邮件发送成功!请注意查收!');
} else {
lgalert.alertInfo(data['message']);
clalert.alertInfo(data['message']);
}
},
'fail': function (error) {
lgalert.alertNetworkError();
clalert.alertNetworkError();
}
});
});
......@@ -84,23 +84,23 @@ $(function () {
var email = emailE.val();
var captcha = captchaE.val();
lgajax.post({
clajax.post({
'url': '/cms/resetemail/',
'data': {
'email': email,
'captcha': captcha
},
'success': function (data) {
if (data['code'] == 200) {
if (data['code'] === 200) {
emailE.val("");
captchaE.val("");
lgalert.alertSuccessToast('恭喜!邮箱修改成功!');
clalert.alertSuccessToast('恭喜!邮箱修改成功!');
} else {
lgalert.alertInfo(data['message']);
clalert.alertInfo(data['message']);
}
},
'fail': function (error) {
lgalert.alertNetworkError();
clalert.alertNetworkError();
}
});
});
......
......@@ -9,11 +9,7 @@
{% endblock %}
{% block head %}
<style>
.form-container {
width: 300px;
}
</style>
<script src="{{ url_for('static', filename='cms/js/resetemail.js') }}"></script>
{% endblock %}
{% block content %}
......
......@@ -9,11 +9,6 @@
{% endblock %}
{% block head %}
<style>
.form-container {
width: 300px;
}
</style>
<script src="{{ url_for('static', filename='cms/js/resetpwd.js') }}"></script>
{% endblock %}
......
import redis
# 连接Redis数据库
r = redis.StrictRedis(host='localhost', port=6379, db=0, decode_responses=True)
def save_captcha(key, value, timeout=300):
'''把验证码存到Redis'''
return r.set(key, value, timeout)
def get_captcha(key):
'''从Redis中取验证码'''
return r.get(key)
def delete_captcha(key):
return r.delete(key)
import random
def get_random_captcha(num):
'''生成随机验证码'''
code = ''
for i in range(num):
num = str(random.randint(0, 9))
upper = chr(random.randint(65, 90))
lower = chr(random.randint(97, 122))
lst = [num, upper, lower]
ret = random.choice(lst)
code = ''.join([code, ret])
return code
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册