| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- # -*- coding: utf-8 -*-
- """账号与权限:密码哈希、会话、角色权限表
- 只依赖标准库。密码用 PBKDF2-HMAC-SHA256,每个账号独立盐值。
- """
- import hashlib
- import hmac
- import secrets
- ITERATIONS = 120_000
- # ---------------------------------------------------------------- 角色定义
- # 三级角色,权限逐级递增
- ROLES = {
- "viewer": {"label": "查看", "desc": "只看数据,不能改任何东西", "level": 1},
- "editor": {"label": "运营", "desc": "可导入、同步、导出,不能改判定规则", "level": 2},
- "admin": {"label": "管理员", "desc": "全部权限,含账号管理", "level": 3},
- }
- ROLE_ORDER = ["admin", "editor", "viewer"]
- # 权限点
- PERMS = {
- "view": "查看数据",
- "export": "导出原始文件",
- "import": "导入数据",
- "sync": "同步生意经数据",
- "config": "修改指标阈值 / 文案",
- "users": "账号管理",
- }
- # 角色 → 拥有的权限
- GRANTS = {
- "viewer": {"view"},
- "editor": {"view", "export", "import", "sync"},
- "admin": {"view", "export", "import", "sync", "config", "users"},
- }
- def can(role, perm):
- return perm in GRANTS.get(role or "", set())
- def role_label(role):
- return ROLES.get(role or "", {}).get("label", role or "-")
- # ---------------------------------------------------------------- 密码
- def hash_password(password, salt=None):
- """返回 (hash_hex, salt_hex)"""
- salt = salt or secrets.token_hex(16)
- digest = hashlib.pbkdf2_hmac("sha256", password.encode("utf-8"),
- salt.encode("utf-8"), ITERATIONS)
- return digest.hex(), salt
- def verify_password(password, stored_hash, salt):
- if not stored_hash or not salt:
- return False
- digest, _ = hash_password(password, salt)
- return hmac.compare_digest(digest, stored_hash)
- def check_strength(password):
- """返回 (是否合格, 提示)"""
- if not password or len(password) < 6:
- return False, "密码至少 6 位"
- if password.isdigit():
- return False, "密码不能全是数字"
- return True, ""
- # ---------------------------------------------------------------- 会话
- def new_token():
- return secrets.token_urlsafe(32)
- def hash_token(token):
- """会话令牌在库里只存哈希,泄露数据库也拿不到可用的 cookie"""
- return hashlib.sha256(token.encode("utf-8")).hexdigest()
|