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:
Binary file not shown.
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user