Files
TODO_list_system/backend/routes/auth.py
beabigegg b0c86302ff 1ST
2025-08-29 16:25:46 +08:00

175 lines
6.0 KiB
Python

from flask import Blueprint, request, jsonify
from flask_jwt_extended import (
create_access_token, create_refresh_token,
jwt_required, get_jwt_identity, get_jwt
)
from datetime import datetime, timedelta
from flask import current_app
from models import db, TodoUserPref
from utils.logger import get_logger
auth_bp = Blueprint('auth', __name__)
logger = get_logger(__name__)
@auth_bp.route('/login', methods=['POST'])
def login():
"""AD/LDAP Login"""
try:
data = request.get_json()
username = data.get('username', '').strip()
password = data.get('password', '')
if not username or not password:
return jsonify({'error': 'Username and password required'}), 400
# Authenticate with LDAP (or mock for development)
try:
if current_app.config.get('USE_MOCK_LDAP', False):
from utils.mock_ldap import authenticate_user
logger.info("Using Mock LDAP for development")
else:
from utils.ldap_utils import authenticate_user
logger.info("Using real LDAP authentication")
user_info = authenticate_user(username, password)
except Exception as e:
logger.error(f"LDAP authentication error, falling back to mock: {str(e)}")
from utils.mock_ldap import authenticate_user
user_info = authenticate_user(username, password)
if not user_info:
logger.warning(f"Failed login attempt for user: {username}")
return jsonify({'error': 'Invalid credentials'}), 401
ad_account = user_info['ad_account']
# Get or create user preferences
user_pref = TodoUserPref.query.filter_by(ad_account=ad_account).first()
if not user_pref:
user_pref = TodoUserPref(
ad_account=ad_account,
email=user_info['email'],
display_name=user_info['display_name']
)
db.session.add(user_pref)
db.session.commit()
logger.info(f"Created new user preference for: {ad_account}")
else:
# Update user info if changed
if user_pref.email != user_info['email'] or user_pref.display_name != user_info['display_name']:
user_pref.email = user_info['email']
user_pref.display_name = user_info['display_name']
user_pref.updated_at = datetime.utcnow()
db.session.commit()
# Create tokens
access_token = create_access_token(
identity=ad_account,
additional_claims={
'display_name': user_info['display_name'],
'email': user_info['email']
}
)
refresh_token = create_refresh_token(identity=ad_account)
logger.info(f"Successful login for user: {ad_account}")
return jsonify({
'access_token': access_token,
'refresh_token': refresh_token,
'user': {
'ad_account': ad_account,
'display_name': user_info['display_name'],
'email': user_info['email'],
'theme': user_pref.theme,
'language': user_pref.language
}
}), 200
except Exception as e:
logger.error(f"Login error: {str(e)}")
return jsonify({'error': 'Authentication failed'}), 500
@auth_bp.route('/refresh', methods=['POST'])
@jwt_required(refresh=True)
def refresh():
"""Refresh access token"""
try:
identity = get_jwt_identity()
# Get user info
user_pref = TodoUserPref.query.filter_by(ad_account=identity).first()
if not user_pref:
return jsonify({'error': 'User not found'}), 404
access_token = create_access_token(
identity=identity,
additional_claims={
'display_name': user_pref.display_name,
'email': user_pref.email
}
)
return jsonify({'access_token': access_token}), 200
except Exception as e:
logger.error(f"Token refresh error: {str(e)}")
return jsonify({'error': 'Token refresh failed'}), 500
@auth_bp.route('/logout', methods=['POST'])
@jwt_required()
def logout():
"""Logout (client should remove tokens)"""
try:
identity = get_jwt_identity()
logger.info(f"User logged out: {identity}")
# In production, you might want to blacklist the token here
# For now, we'll rely on client-side token removal
return jsonify({'message': 'Logged out successfully'}), 200
except Exception as e:
logger.error(f"Logout error: {str(e)}")
return jsonify({'error': 'Logout failed'}), 500
@auth_bp.route('/me', methods=['GET'])
@jwt_required()
def get_current_user():
"""Get current user information"""
try:
identity = get_jwt_identity()
claims = get_jwt()
user_pref = TodoUserPref.query.filter_by(ad_account=identity).first()
if not user_pref:
return jsonify({'error': 'User not found'}), 404
return jsonify({
'ad_account': identity,
'display_name': claims.get('display_name', user_pref.display_name),
'email': claims.get('email', user_pref.email),
'preferences': user_pref.to_dict()
}), 200
except Exception as e:
logger.error(f"Get current user error: {str(e)}")
return jsonify({'error': 'Failed to get user information'}), 500
@auth_bp.route('/validate', methods=['GET'])
@jwt_required()
def validate_token():
"""Validate JWT token"""
try:
identity = get_jwt_identity()
claims = get_jwt()
return jsonify({
'valid': True,
'identity': identity,
'claims': claims
}), 200
except Exception as e:
logger.error(f"Token validation error: {str(e)}")
return jsonify({'valid': False}), 401