a
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
认证相关路由和装饰器 —— 双模式认证(本地 Session + SSO Cookie)
|
||||
"""
|
||||
from functools import wraps
|
||||
from datetime import timedelta
|
||||
from flask import Blueprint, request, jsonify, session
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from models import User, db
|
||||
from sso_client import get_user_from_sso_cookie
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
|
||||
def api_login_required(f):
|
||||
"""API 登录检查装饰器 - 双模式认证
|
||||
1. 优先检查本地 Flask-Login Session
|
||||
2. 无 Session 则检查 SSO Cookie,本地验签后查本地 User 表
|
||||
"""
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
# 模式一:本地 Session
|
||||
if current_user.is_authenticated:
|
||||
return f(*args, **kwargs)
|
||||
|
||||
# 模式二:SSO Cookie
|
||||
sso_user = get_user_from_sso_cookie(request)
|
||||
if sso_user:
|
||||
username = sso_user.get("username")
|
||||
user = User.query.filter_by(username=username).first()
|
||||
if user:
|
||||
# 自动登录到本地 Session,后续请求走模式一
|
||||
login_user(user, remember=True, duration=timedelta(days=30))
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return jsonify({
|
||||
'error': 'Unauthorized',
|
||||
'message': '请先登录',
|
||||
'code': 401
|
||||
}), 401
|
||||
return decorated_function
|
||||
|
||||
|
||||
@auth_bp.route('/api/auth/login', methods=['POST'])
|
||||
def login():
|
||||
"""用户登录 API"""
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return jsonify({'error': '请求数据为空'}), 400
|
||||
|
||||
username = data.get('username', '').strip()
|
||||
password = data.get('password', '').strip()
|
||||
|
||||
if not username or not password:
|
||||
return jsonify({'error': '用户名和密码不能为空'}), 400
|
||||
|
||||
user = User.query.filter_by(username=username).first()
|
||||
|
||||
if not user or not user.check_password(password):
|
||||
return jsonify({'error': '用户名或密码错误'}), 401
|
||||
|
||||
# 登录用户(记住我 30 天)
|
||||
login_user(user, remember=True, duration=timedelta(days=30))
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '登录成功',
|
||||
'user': user.to_dict()
|
||||
})
|
||||
|
||||
|
||||
@auth_bp.route('/api/auth/logout', methods=['POST'])
|
||||
def logout():
|
||||
"""用户登出 API —— 不要求登录态,确保未登录也能退出"""
|
||||
if current_user.is_authenticated:
|
||||
logout_user()
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '已登出'
|
||||
})
|
||||
|
||||
|
||||
@auth_bp.route('/api/auth/status')
|
||||
def auth_status():
|
||||
"""检查登录状态 API —— 双模式"""
|
||||
# 模式一:本地 Session
|
||||
if current_user.is_authenticated:
|
||||
return jsonify({
|
||||
'authenticated': True,
|
||||
'user': current_user.to_dict()
|
||||
})
|
||||
|
||||
# 模式二:SSO Cookie
|
||||
sso_user = get_user_from_sso_cookie(request)
|
||||
if sso_user:
|
||||
username = sso_user.get("username")
|
||||
user = User.query.filter_by(username=username).first()
|
||||
if user:
|
||||
return jsonify({
|
||||
'authenticated': True,
|
||||
'user': user.to_dict()
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'authenticated': False,
|
||||
'user': None
|
||||
})
|
||||
Reference in New Issue
Block a user