Implement Casdoor authentication integration, including login and callback routes. Update environment variables for Casdoor configuration. Modify login page to support Casdoor login option and enhance UI styles. Adjust uWSGI port settings and update application logging for user actions.

This commit is contained in:
2025-12-10 15:08:04 +08:00
parent 0f41063688
commit bb39314940
16 changed files with 541 additions and 2148 deletions
Binary file not shown.
+130
View File
@@ -0,0 +1,130 @@
"""
Casdoor 认证工具模块
用于处理 Casdoor OAuth/OIDC 认证流程
"""
import requests
import urllib.parse
from flask import session, current_app
import secrets
class CasdoorAuth:
"""Casdoor 认证处理类"""
def __init__(self, app=None):
self.app = app
if app:
self.init_app(app)
def init_app(self, app):
"""初始化应用配置"""
self.endpoint = app.config.get('CASDOOR_ENDPOINT')
self.client_id = app.config.get('CASDOOR_CLIENT_ID')
self.client_secret = app.config.get('CASDOOR_CLIENT_SECRET')
self.organization_name = app.config.get('CASDOOR_ORGANIZATION_NAME', 'built-in')
self.application_name = app.config.get('CASDOOR_APPLICATION_NAME', 'app-built-in')
self.redirect_uri = app.config.get('CASDOOR_REDIRECT_URI')
def get_authorization_url(self, state=None):
"""
生成 Casdoor 授权 URL
Args:
state: 状态参数,用于防止 CSRF 攻击
Returns:
str: 授权 URL
"""
if not state:
state = secrets.token_urlsafe(32)
session['casdoor_state'] = state
params = {
'client_id': self.client_id,
'response_type': 'code',
'redirect_uri': self.redirect_uri,
'scope': 'openid profile email phone',
'state': state
}
auth_url = f"{self.endpoint}/login/oauth/authorize"
return f"{auth_url}?{urllib.parse.urlencode(params)}"
def get_token(self, code):
"""
使用授权码获取访问令牌
Args:
code: 授权码
Returns:
dict: 包含 access_token 和 id_token 的字典
"""
token_url = f"{self.endpoint}/api/login/oauth/access_token"
data = {
'grant_type': 'authorization_code',
'client_id': self.client_id,
'client_secret': self.client_secret,
'code': code,
'redirect_uri': self.redirect_uri
}
try:
response = requests.post(token_url, data=data)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
try:
current_app.logger.error(f"获取 Casdoor token 失败: {str(e)}")
except:
pass # 如果无法记录日志,忽略错误
return None
def get_user_info(self, access_token):
"""
使用访问令牌获取用户信息
Args:
access_token: 访问令牌
Returns:
dict: 用户信息字典
"""
user_info_url = f"{self.endpoint}/api/userinfo"
headers = {
'Authorization': f'Bearer {access_token}'
}
try:
response = requests.get(user_info_url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
try:
current_app.logger.error(f"获取 Casdoor 用户信息失败: {str(e)}")
except:
pass # 如果无法记录日志,忽略错误
return None
def verify_state(self, state):
"""
验证 state 参数,防止 CSRF 攻击
Args:
state: 从回调中获取的 state 参数
Returns:
bool: 验证是否通过
"""
stored_state = session.get('casdoor_state')
if stored_state and stored_state == state:
session.pop('casdoor_state', None)
return True
return False
# 创建全局实例
casdoor_auth = CasdoorAuth()