flask权限管理

蚀纹迭代
• 阅读 16123

基本的flask权限管理

1. 验证字段与密码的存储

权限管理的基础就是验证字段(用户名or邮箱...)以及密码,
所以首先需要考虑验证字段和密码的存储。(这里使用flask-sqlalchemy作为ORM)

model:User

class User(db.Model):
    """用户类"""
    id = db.Column(db.Integer, primary_key=True)
    # 用户名字符串存储即可
    username = db.Column(db.String(164))
    # 密码一定要注意
    # 密码不允许在数据库中明文存储
    password_hash = db.Column(db.String(164))
    ......

    # 所以需要对用户传入的明文密码进行加密
    @property
    def password(self):
        """
        password属性函数
        不允许直接读取原始值
        """
        return "密码不是可读形式!"

    @password.setter
    def password(self, password):
        """
        设置密码hash值
        """
        self.password_hash = werkzeug.security.generate_password_hash(password)

    def verify_password(self, password):
        """
        将用户输入的密码明文与数据库比对
        """
        return werkzeug.security.check_password_hash(password)

2. 用户权限与角色的设置

我一般将用户权限设置为16进制的值, 而用户角色则是用户权限(16进制的值)的异或(|)运算,
比如我设置以下2个权限:

class Permission:
    """
    权限表
    """
    COMMENT = 0x01  # 评论
    MODERATE_COMMENT = 0x02  # 移除评论

那么可设置如下角色, 并建立和User的多对一关系:

class Role(db.Model):
    """
    用户角色
    """
    id = db.Column(db.Integer, primary_key=True)
    # 该用户角色名称
    name = db.Column(db.String(164))
    # 该用户角色是否为默认
    default = db.Column(db.Boolean, default=False, index=True)
    # 该用户角色对应的权限
    permissions = db.Column(db.Integer)
    # 该用户角色和用户的关系
    # 角色为该用户角色的所有用户
    users = db.relationship('User', backref='role', lazy='dynamic')

    @staticmethod
    def insert_roles():
        """
        创建用户角色
        """
        roles = {
            # 定义了两个用户角色(User, Admin)
            'User': (Permission.COMMENT, True),
            'Admin': (Permission.COMMENT |
                      Permission.MODERATE_COMMENT, False)
        }
        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                # 如果用户角色没有创建: 创建用户角色
                role = Role(name=r)
            role.permissions = roles[r][0]
            role.default = roles[r][1]
            db.session.add(role)
            db.session.commit()

现在只需在User里创建一个指向用户角色的外键即可

calss User(db.Model):
    ......
    role_id = db.Column(db.Integer, db.ForeignKey('role.id'))
    ......

flask权限在具体场景中的应用

应用在具体场景, 使用相关扩展就不可避免了

1. 处理登录(flask-login)

对于flask登录,使用flask-login是较为简单的办法,
但是个人感觉flask-login不是很灵活(下面的扩展也是,
毕竟扩展的目的是通用)。<br/>
这里就不具体说明如何集成flask-login了,主要说如何使用flask-login<br/>

用户登录

使用flask-login提供的login_user, current_user

@auth.route('/login/', methods=["POST", "GET"])
def login():
    """用户登录"""
    next = get_redirect_target()
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is not None and user.verify_password:
            login_user(user)
            return redirect_back('default redirect back url', id=current_user.id)
        flash("用户名或密码错误!")
    return render_template("login.html", form=form, next=next)

用户登出

使用flask-login提供的logout_user

@login_required
@auth.route('/logout/')
def logout():
    """用户登出"""
    logout_user()
    return redirect("重定向路由")

2. 处理HTTPBasicAuth(flask-httpauth)

flask-httpauth 可以帮助我们处理一些基本的权限管理,
同flask-login一样, flask-httpauth 也提供了一个login_required装饰器,
通过auth对象调用即可控制用户名, 密码的登录权限控制。

token权限管理

这里比较复杂的地方就是token的权限管理了, 因为此处没有拓展可用(扩展是为了通用性, 但是token不是强制使用的),
都是自己踩坑弄出来的, 写在博客里做一个纪录。

什么是token

token是用户信息(一般是用户id,
具有唯一标识作用)的标识。对用户id进行签名加密(我一般使用itsdangerous模块),
例如:

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

# 此函数为User类的成员函数
def generate_auth_token(self):
    s = Serializer(
        current_app.config['SECRET_KEY'],  # 密钥很重要
        expiration  # Token的寿命
    )
    # 用获取的签名加密用户id信息
    return s.dumps({'id': self.id})
为什么需要token

token 一般使用在API的场景中, 此时客户端和服务器端是分离的,
数据信息通过API进行传递, 他人很容易就可以拦截API并获取验证头部的authorization字段,
从而获取用户名和密码(一般是base64进行了加密, 但是很容易被破解), 这样是极不安全的。<br/>
之所以需要验证, 其实就是为了标识这个用户是谁, 而id就是一个最好的标识,
所以通过用户的用户名和密码请求token(这样用户名和密码不会频繁被发送),
用获取的token放在API头部进行传递, 这样即使被拦截,
也不会获取用户的敏感信息(用户名, 密码), 即使token被他人使用,
也会因为token的寿命而使破坏性大大降低。

token的使用: 发送token

token需放在Authorization头部, 采用如下形式发送:

"Basic token"
token的使用: 解析token

依然采用itsdangerous模块, 这里密钥就很重要了,
只有与加密相同的密钥才可以解析token。

# User类的一个静态成员函数
@staticmethod
def verify_auth_token(token):
    # 获取签名
    s = Serializer(current_app.config["SECRET_KEY"])
    try:
        data = s.loads(token)  # 用签名解析token
    except:
        return None
    # 返回该token标识的用户
    return User.query.filter_by(id=data['id'])
基于token的权限管理

这里主要是区别普通用户和管理员用户, 因为有些特定的操作是只有管理员可以进行的。<br/>

1.在User类里添加管理员判断函数 <br/>

def can(self, permission):
    # 判断用户是否具备某权限
    return self.role is not None and (self.role.permissions & permissions) = permissions

def is_adminstractor(self):
    # 判断用户是否具备管理员权限
    return self.can(Permission.COMMENT | Permission.MODERATE_COMMENT)

2.创建管理员权限判断装饰器<br/>

from functools import wraps
from flask import request, g

def admin_required(f):
    @wraps(f)
    def decorator(*args, **kwargs):
        token_header = request.headers.get('authorization')
        token = token_header[6:]  # 去掉格式中的Basic
        if token:
            g.current_user = User.verify_auth_token(token)
            if g.current_user.is_adminstractor():
                return f(*args, **kwargs)
            else:
                abort(403)
    return decorator

然后就可以使用admin_required装饰器进行权限管理了,
这里有个坑提一下就是flask-httpauth会自己添加Basic,
所以使用该扩展的地方就不必考虑token格式的问题了。

总结

flask权限管理比较烦的地方就是如何使不同的权限管理扩展一起工作,
以及使用了扩展以后对于定制自己的东西该如何写,
这时候还是最好去看使用相应扩展的源码, 然后以此为基础, 展开自己的工作吧!

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
mysql服务设置远程连接 解决1251 client does not support ..问题
一、前期准备1、虚拟机/物理机  mysql环境(非本机)2、本机navicat软件(验证远程连接)二、mysql配置1、在远程主机的本机 使用root用户连接mysqlmysqlurootp备注:mysqlu最高权限用户名p 再输入密码进入!(http
Stella981 Stella981
3年前
Keycloak 基本功能
Keycloak是一个致力于解决应用和服务身份验证与访问管理的开源工具。可以通过简单的配置达到保护应用和服务的目的。用户管理你的应用不需要开发登录模块,验证用户和保存用户。Keycloak开发了用户管理,登录,注册,密码策略,安全问题,二步验证,密码重置等功能。登录,注册界面所需字段都是可配置,可自定义的。用户角色,权限管理功能,用户组功能。用户
Stella981 Stella981
3年前
Shiro要点概览与SpringBoot整合实例
1\.简介概念说明Subject主体,简化点说就是用户实体PrincipalSubject的唯一标识,如id、用户名、手机号、邮箱等Credential凭证信息,主体证明自己的东西,如密码、证书等Authenticator认证器,对Subject身份进行认证,例如验证用户的用户名和密码是否匹配Aut
Wesley13 Wesley13
3年前
mysql5.7 修改root密码无法登陆原因
升级的mysql5.7修改完root账户密码后仍然无法登陆,查阅资料可能和user表的plugin字段为空有关。1、首先将my.ini中加入在\mysqld\节点上加skipgranttables主要作用是:跳过表中的验证,可以无密码登陆。2、登录之后查询plugin字段值:mysqlselectpluginf
Wesley13 Wesley13
3年前
mysql用户
1\.学会能按着需求创建一个帐号2\.知道连接字符串是什么样3\.密码密码怎么恢复mysql用户权限介绍mysql用户管理 !(https://oscimg.oschina.net/oscnet/368d3c1e00a0a9515545c2962660a27a080.png)!(https://oscimg.oschin
Easter79 Easter79
3年前
Springmvc+mybatis+shiro+Dubbo+ZooKeeper+Redis+KafKa j2ee分布式架构
框架简介主要定位于互联网企业架构,已内置企业信息化系统的基础功能和高效的代码生成工具,包括:系统权限组件、数据权限组件、数据字典组件、核心工具组件、视图操作组件、工作流组件组件、代码生成等。采用分层设计、双重验证、提交数据安全编码、密码加密、访问验证、数据权限验证。平台简介    是一个分布式的框架,提供项目模块化、服务化、热插拔的思想,高
Wesley13 Wesley13
3年前
2.权限管理准备工作:你应该知道的ASP.NET网站最基本的安全措施!
一.ASP.NET与 IIS一起使用的身份验证方法来验证用户凭据(如用户名和密码):1.Windows:基本、摘要式或集成Windows身份验证(NTLM或Kerberos)。2.Forms身份验证,您可以通过该身份验证在您的应用程序中创建登录页并管理身份验证。3.客户证书身份验证二.ASP.NET网站最基本的安全措施:
Wesley13 Wesley13
3年前
MySQL 8.0.11 中使用 grant ... identified by 时 error 1064 near 'identified by '密码'' a...
(1)问题:当使用 grant权限列表on数据库to'用户名'@'访问主机'identifiedby'密码';时会出现"......near'identifiedby'密码''atline1"这个错误(2)原因:因为新版的的mysql版本已经将创建账户和赋予权限的方式分开了
Wesley13 Wesley13
3年前
linux修改用户密码
直接修改密码 通过whoami可以查看当前登陆的用户。直接输入 passwd  回车,输入2次密码就是修改当前的用户名(提示all authentication tokens updated sucessfully 表示密码修改OK) passwd修改某个用户的密码(注意要管理员权限或者本账号)
taskbuilder taskbuilder
8个月前
任擎Tasgine应用服务引擎
1任擎简介在开发一个企业级管理软件时,首先要考虑的是系统底层的基础性功能,例如组织结构管理、角色管理、操作权限管理、身份验证、系统日志记录和查询、系统UI界面、系统门户、消息推送、文档存储等等。另外,还得考虑系统的稳定性、兼容性、安全性、可扩展性和性能等,
融云IM即时通讯 融云IM即时通讯
6个月前
融云 IM 干货丨云存储的安全措施有哪些?
云存储的安全措施云存储的安全性是确保数据机密性、完整性和可用性的关键。以下是一些常见的云存储安全措施:1.访问控制与权限管理身份认证:通过密码、多因素认证(如短信验证码、生物识别等)确认用户身份,确保只有授权用户才能访问云存储数据。基于角色的访问控制(RB