Flask-Login + 角色权限:一套可扩展的访问控制

拒绝在每个视图里手写 if role != admin,把权限判断收敛到装饰器与服务层。

Flask-Login + 角色权限:一套可扩展的访问控制

权限代码最怕两件事:判断散落在各处,以及新增角色时到处补条件。

用户模型的三件事

  1. 密码哈希:只存哈希,永不存明文
  2. 角色标识:普通用户、会员、管理员
  3. 权益判断:会员是否在有效期

把权益判断写成属性,模板与服务层都能复用:

@property
def membership_active(self):
    if self.is_admin:
        return True
    return self.role == "member" and self.membership_expires_at > now()

装饰器收敛判断

def role_required(*roles):
    def decorator(view):
        @wraps(view)
        @login_required
        def wrapped(*args, **kwargs):
            if not current_user.has_role(*roles):
                raise ForbiddenError()
            return view(*args, **kwargs)
        return wrapped
    return decorator

后台路由统一使用 @admin_required,业务层再做一次权益校验,形成双重保险。

常见坑

  • 不要用 is_active 作为业务字段,它与 Flask-Login 的接口冲突
  • 修改角色时应防止移除最后一个管理员
  • 登录跳转参数必须校验,避免开放重定向

权限系统不需要复杂,但必须只有一个判断入口。