from flask import render_template, request, redirect, url_for, flash, session from flask_login import login_user, login_required, logout_user, current_user from scripts.models import db, User from utils.casdoor_auth import casdoor_auth def init_auth_routes(app): # 初始化 Casdoor 认证 casdoor_auth.init_app(app) @app.route('/login', methods=['GET', 'POST']) def login(): # 已登录直接进入仪表盘,否则跳转 Casdoor 登录 if current_user.is_authenticated: return redirect(url_for('dashboard')) return redirect(url_for('casdoor_login')) @app.route('/casdoor/login') def casdoor_login(): """Casdoor 登录入口,重定向到 Casdoor 授权页面""" if not app.config.get('CASDOOR_CLIENT_ID'): flash('Casdoor 未配置,请使用手机号登录') return redirect(url_for('login')) auth_url = casdoor_auth.get_authorization_url() app.logger.info('重定向到 Casdoor 授权页面') return redirect(auth_url) @app.route('/callback') def casdoor_callback(): """Casdoor OAuth 回调处理""" code = request.args.get('code') state = request.args.get('state') error = request.args.get('error') if error: app.logger.error(f'Casdoor 认证失败: {error}') flash(f'登录失败: {error}') return redirect(url_for('login')) if not code: app.logger.warning('Casdoor 回调缺少授权码') flash('登录失败:未收到授权码') return redirect(url_for('login')) # 验证 state 参数 if not casdoor_auth.verify_state(state): app.logger.warning('Casdoor state 验证失败,可能存在 CSRF 攻击') flash('登录失败:安全验证失败') return redirect(url_for('login')) # 获取访问令牌 token_data = casdoor_auth.get_token(code) if not token_data or 'access_token' not in token_data: app.logger.error('获取 Casdoor token 失败') flash('登录失败:无法获取访问令牌') return redirect(url_for('login')) access_token = token_data['access_token'] # 获取用户信息 user_info = casdoor_auth.get_user_info(access_token) if not user_info: app.logger.error('获取 Casdoor 用户信息失败') flash('登录失败:无法获取用户信息') return redirect(url_for('login')) # 从 Casdoor 用户信息中提取数据 # Casdoor 返回的用户信息可能包含:name, email, phone, id 等字段 casdoor_id = user_info.get('sub') or user_info.get('id') or user_info.get('name') phone = user_info.get('phone') or user_info.get('phoneNumber') or casdoor_id name = user_info.get('name') or user_info.get('displayName') or '未知用户' app.logger.info(f'Casdoor 用户信息: {user_info}') # 查找或创建本地用户 user = User.query.filter_by(phone=phone).first() if not user: # 如果用户不存在,创建新用户 user = User( phone=phone, name=name, branch=user_info.get('affiliation', ''), role=user_info.get('type', '') ) db.session.add(user) db.session.commit() app.logger.info(f'创建新用户: {name}({phone})') else: # 更新用户信息 user.name = name if user_info.get('affiliation'): user.branch = user_info.get('affiliation') if user_info.get('type'): user.role = user_info.get('type') db.session.commit() app.logger.info(f'更新用户信息: {name}({phone})') # 登录用户 login_user(user) app.logger.info(f'用户 {user.name}({user.phone}) 通过 Casdoor 登录成功') return redirect(url_for('dashboard')) @app.route('/logout') @login_required def logout(): app.logger.info(f'用户 {current_user.name}({current_user.phone}) 登出') logout_user() # 如果配置了 Casdoor,可以重定向到 Casdoor 登出页面 if app.config.get('CASDOOR_ENDPOINT'): logout_url = f"{app.config.get('CASDOOR_ENDPOINT')}/logout" return redirect(logout_url) return redirect(url_for('login'))