Files
crawler-plugin/backend/utils/auth.py
2026-04-30 11:36:58 +08:00

114 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
认证装饰器与 session 校验
"""
from functools import wraps
from flask import request, redirect, url_for, session, jsonify, g
from utils.db import get_db
def is_session_user_valid():
"""校验 session 中的 user_id 是否仍存在;不存在则清空 session。"""
uid = session.get('user_id')
if not uid:
return False
cached_user = getattr(g, '_current_user_row', None)
if cached_user and cached_user.get('id') == uid:
return True
try:
conn = get_db()
with conn.cursor() as cur:
cur.execute(
"SELECT id, username, is_admin, role, created_by_id FROM users WHERE id = %s",
(uid,)
)
row = cur.fetchone()
conn.close()
if not row:
session.clear()
return False
g._current_user_row = row
return True
except Exception:
session.clear()
return False
def get_current_admin_role():
"""返回当前登录用户的管理角色super_admin / admin / None。"""
uid = session.get('user_id')
if not uid:
return None, None
try:
row = getattr(g, '_current_user_row', None)
if not row or row.get('id') != uid:
conn = get_db()
with conn.cursor() as cur:
cur.execute(
"SELECT id, username, is_admin, role, created_by_id FROM users WHERE id = %s",
(uid,)
)
row = cur.fetchone()
conn.close()
if not row:
return None, None
g._current_user_row = row
role = (row.get('role') or '').strip().lower()
if not role:
role = 'super_admin' if row.get('is_admin') and row.get('created_by_id') is None else (
'admin' if row.get('is_admin') else 'normal'
)
return role, row
except Exception:
return None, None
def is_current_user_admin():
role, _ = get_current_admin_role()
return role in ('super_admin', 'admin')
def _is_ajax_request():
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return True
if request.path.startswith('/api/'):
return True
accept = (request.headers.get('Accept') or '').lower()
if 'application/json' in accept:
return True
return False
def login_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if not session.get('user_id') or not is_session_user_valid():
if _is_ajax_request():
return jsonify({'success': False, 'error': '未登录'}), 401
return redirect(url_for('auth.login'))
return f(*args, **kwargs)
return decorated
def admin_required(f):
@wraps(f)
def decorated(*args, **kwargs):
if not session.get('user_id') or not is_session_user_valid():
if _is_ajax_request():
return jsonify({'success': False, 'error': '未登录'}), 401
return redirect(url_for('auth.login'))
try:
role, _ = get_current_admin_role()
if role not in ('super_admin', 'admin'):
if _is_ajax_request():
return jsonify({'success': False, 'error': '需要管理员权限'}), 403
return redirect(url_for('auth.login'))
except Exception as exc:
if _is_ajax_request():
return jsonify({'success': False, 'error': str(exc)}), 500
return redirect(url_for('auth.login'))
return f(*args, **kwargs)
return decorated