数据库优化
- 数据库其实存在
连接池
的
- 连接池维护着一定数量的数据库连接
current_app
current_app只有在项目启动之后才能使用 , 项目没有启动时不能使用
CSRF攻击示意图

防止CSRF攻击
- 在客户端向后端请求界面数据的时候,后端会往响应中的 cookie 中设置 csrf_token 的值
- 在 Form 表单中添加一个隐藏的的字段,值也是 csrf_token
- 在用户点击提交的时候,会带上这两个值向后台发起请求
- 后端接受到请求,以会以下几件事件:
- 从 cookie中取出 csrf_token
- 从 表单数据中取出来隐藏的 csrf_token 的值
- 进行对比
- 如果比较之后两值一样,那么代表是正常的请求,如果没取到或者比较不一样,代表不是正常的请求,不执行下一步操作
使用内置的密码加密解密
1 2 3 4 5 6 7 8 9 10 11
| from werkzeug.security import generate_password_hash, check_password_hash
psw = request.form.get('password') hash_psw = generate_password_hash(psw)
student = Student.query.filter_by(id=123) psw = request.form.get('password') if checkout_password_hash(student.password,psw): return 'ok'
|
上面两个方法应该封装到StudentModel上
1 2 3 4 5 6 7 8 9 10 11 12 13
| class UserOauthModel(db.Model): _password = db.Column(db.String(54), nullable=False)
@property def password(self): return self._password
@password.setter def password(self,psw): self._password = generate_password_hash(psw)
def check_password(self): return checkout_password_hash(self._password,psw)
|
代码复用的方法
flash()方法的本质
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @index_router.route('/login', methods=["GET", "POST", ]) def login(): form = UserOauthForm() if form.validate_on_submit(): form = UserOauthForm(formdata=request.form) user = Cache.get_user(form.data.get('emp_id')) if user: login_user(user) flash(f"欢迎登陆: 工号{user.emp_id}", category="success") return redirect(request.args.get('next') or url_for("user.emp_detail")) else: Cache.update_user(user) return render_template('user/login.html', form=form)
|
1 2 3 4 5 6 7 8 9 10
| {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <div class="alert alert-success" style="text-align: center;"> <button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button> <strong>{{ message }}</strong> </div> {% endfor %} {% endif %} {% endwith %}
|
- flash本质就是session
- 后台的flash函数将信息写入session中 , 前台再从session取出,输出到相应的位置 , 然后再次传入后台的时候就将这个session去除
- 这就能解释flash()的功能 : 将信息输出到下一个页面,而且只会输出一次
UserModel关于密码的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class User(db.Model): id = db.Column(db.Integer , primerry_key=True) username = db.Column(db.String(32),unique=True) _password = db.Column(db.String(256)) permission = db.Column(db.Integer , default=PERMISSION_NONE)
@property def password(self): raise Exception("cant access")
@password.setter def password(self,psw): self._password = genrate_password_hash(psw) def check_password(self,psw): return check_password_hash(self._password,psw)
def check_permission(self,permission): """ 检测是否有某个权限 """ if BLACK_USER & self.permission == BLACK_USER: return False return permission & self.permission == permission
|
1 2 3 4
| PERMISSION_NONE = 0 BLACK_USER = 1 COMMON_USER = 2 VIP_USER = 4
|
权限的两种设计
单个字段实现所有功能
类似于Linux权限设计 , 一个字段可以代表多种权限 : rwx
方案一 : Linux权限设计模式
- 完全和Linux中一样 , 使用二进制
- 每一种权限使用一个不重复的二进制确定
- 所有的初始权限值都是2的n次幂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| BLACK_USER = 1 COMMON_USER = 2 VIP_USER = 4
class User: def __init__(self, permission): self.permission = permission
me = User(permission=4)
def check_permissin(user,permission): """ 检测user是否拥有某个权限 """ return user.permission & permission == permission
res = check_permissin(me,VIP_USER) print(res)
|
方案二 : 包含模式
- 只是给一个数值
- 数值越大权限越高 , 包含数值小的所有权限
多表设计权限
- 用户表
- 权限表
- 用户权限表(用户表和权限表多对多的关系)
1 2 3 4 5 6 7 8 9
| class User(db.Model): id = db.Column(db.Integer, primerry_key=True) username = db.Column(db.String(32), unique=True) _password = db.Column(db.String(256))
class Permission(db.Model): p_name = db.Column(db.Integer,db.ForerginKey(User.id)) c_persmission_id = db.Column(db.Integer,db.ForerginKey(Permission.id))
|
使用事务
1 2 3 4 5 6 7 8 9
| try: connect.commit() return 'OK' except Exception as error: print(error) connect.rollback() return 'Err'
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| def hello_transaction(request): try: with transaction.atomic(): pass except Exception as e: transaction.rollback() else: transaction.commit()
return HttpResponse('hello')
def welcome_transaction(request): save_point = transaction.savepoint() try: pass except Exception as e: transaction.savepoint_rollback(save_point) else: transaction.savepoint_commit(save_point)
return HttpResponse('welcome')
|