卢卡
这篇指南将向您介绍如何使用 SAML 2.0 或 OpenID Connect 在 SmartLink 和卢卡之间设置单点登录(SSO)。
先决条件
- 拥有已激活 SSO 模块的卢卡帐户
- 在卢卡上拥有管理员访问权限
- 在 SmartLink 中配置了使用 SAML2 或 OpenID Connect 的应用程序
- 已验证电子邮件域
注意:SSO 需要在您的卢卡合同中激活 SSO 模块。
使用 OpenID Connect 进行配置(推荐)
在 SmartLink 中进行配置
1. 创建应用程序
- 以管理员身份登录到 SmartLink
- 转到 应用程序 → 添加
- 创建一个新应用程序:
- 名称:卢卡
- URL:
https://[your-instance].ilucca.net - 描述:完整的人力资源信息系统套件(Figgo、Pagga、Timmi 等)
- 图标:选择卢卡 图标
2. 配置 OpenID Connect
- 在 认证 选项卡中
- 选择 OpenID Connect
- 记下以下信息:
- 客户端 ID:
lucca-xxxxxx - 客户端密钥:
secret-xxxxxx - 应用程序 ID:
[appid](自动生成的唯一标识符)
- 客户端 ID:
3. 重定向 URL
在 允许的重定向 URL 中添加:
https://[your-instance].ilucca.net/identity/oidc/callback
https://[your-instance].ilucca.net/auth/oidc/callback
在卢卡中进行配置
1. 访问 SSO 设置
- 以管理员身份登录到卢卡
- 转到 配置 → 设置 → 认证
- 点击 单点登录(SSO)
- 选择 OpenID Connect
2. 配置身份提供者
配置以下参数:
- 发现 URL:
https://[your-smartlink].link.vaultys.org/api/oidc/[appid]/.well-known/openid-configuration - 客户端 ID:
lucca-xxxxxx(来自 SmartLink) - 客户端密钥:
secret-xxxxxx(来自 SmartLink) - 范围:
openid profile email groups
3. 属性映射
| 卢卡属性 | OpenID Claim | 必填 |
|---|---|---|
| 电子邮件 | email | ✅ |
| 名字 | given_name | ✅ |
| 姓氏 | family_name | ✅ |
| 工号 | employee_number | ❌ |
| 部门 | department | ❌ |
| 经理 | manager_email | ❌ |
使用 SAML 2.0 进行配置
在 SmartLink 中进行配置
1. 配置 SAML2
- 在卢卡应用程序中
- 选项卡 认证 → SAML2
- 配置:
- 实体 ID:
https://[your-smartlink].link.vaultys.org/[appid] - ACS URL:
https://[your-instance].ilucca.net/identity/saml2/acs - NameID 格式:
emailAddress
- 实体 ID:
2. 获取元数据
记下以下 URL:
- IdP 元数据:
https://[your-smartlink].link.vaultys.org/api/saml2/[appid]/metadata - SSO URL:
https://[your-smartlink].link.vaultys.org/api/saml2/sso/[appid] - SLO URL:
https://[your-smartlink].link.vaultys.org/api/saml2/slo/[appid] - 实体 ID:
https://[your-smartlink].link.vaultys.org/[appid]
在卢卡中进行配置
- 在 配置 → 认证 → SAML 2.0 中
- 导入元数据或手动配置:
- IdP 实体 ID:
[appid] - SSO URL:
https://[your-smartlink].link.vaultys.org/api/saml2/sso/[appid] - X.509 证书:从 SmartLink 导入
- IdP 实体 ID:
卢卡模块配置
Figgo(休假管理)
{
"figgo_settings": {
"auto_provision": true,
"sync_managers": true,
"default_leave_policy": "standard",
"sso_groups_mapping": {
"smartlink-managers": "validateur_n1",
"smartlink-hr": "administrateur_rh",
"smartlink-employees": "collaborateur"
}
}
}
Pagga(工资管理)
{
"pagga_settings": {
"restricted_access": true,
"allowed_groups": ["smartlink-hr", "smartlink-payroll"],
"permissions": {
"smartlink-payroll": ["edit_bulletins", "export_dsn"],
"smartlink-hr": ["view_bulletins", "manage_employees"],
"smartlink-managers": ["view_team_bulletins"]
}
}
}
Timmi(时间管理)
timmi_configuration:
projects:
sync_with_sso_groups: true
default_access: "member"
time_tracking:
mandatory: true
validation_workflow: "manager"
permissions:
smartlink-project-managers:
- create_projects
- manage_budgets
- view_all_timesheets
smartlink-employees:
- submit_timesheet
- view_own_timesheet
Poplee Core RH
{
"poplee_settings": {
"employee_sync": {
"source": "sso",
"update_on_login": true,
"fields_mapping": {
"department": "{{department}}",
"job_title": "{{title}}",
"manager": "{{manager_email}}",
"location": "{{office_location}}"
}
}
}
}
数据同步
使用 SSO 的卢卡 API
const axios = require('axios');
class LuccaAPIClient {
constructor(apiKey, domain) {
this.apiKey = apiKey;
this.baseUrl = `https://${domain}.ilucca.net/api/v3`;
}
async syncUserFromSSO(ssoUserData) {
// 通过电子邮件查找用户
const user = await this.getUserByEmail(ssoUserData.email);
if (!user) {
// 创建用户
return await this.createUser({
mail: ssoUserData.email,
firstName: ssoUserData.given_name,
lastName: ssoUserData.family_name,
department: ssoUserData.department,
authenticationMode: 'sso'
});
} else {
// 更新用户
return await this.updateUser(user.id, {
department: ssoUserData.department,
jobTitle: ssoUserData.title
});
}
}
async getUserByEmail(email) {
const response = await axios.get(`${this.baseUrl}/users`, {
headers: { 'Authorization': `lucca application=${this.apiKey}` },
params: { mail: email }
});
return response.data.items[0];
}
}
卢卡 Webhooks
// 用于接收卢卡 Webhooks 的端点
app.post('/webhook/lucca', async (req, res) => {
const { event, data } = req.body;
switch(event) {
case 'user.created':
// 如有必要,与 SmartLink 同步
await syncNewUserToSmartLink(data);
break;
case 'leave.approved':
// 通过 SmartLink 发送通知
await sendNotification(data.userId, '您的休假申请已获批准');
break;
case 'timesheet.submitted':
// 触发验证工作流程
await triggerValidationWorkflow(data);
break;
}
res.status(200).json({ success: true });
});
配置测试
1. 连接测试
- 从卢卡注销
- 转到
https://[your-instance].ilucca.net - 点击 使用 SSO 登录
- 输入您的工作邮箱
- 通过 SmartLink 进行身份验证
- 检查对各个卢卡模块的访问权限
2. 权限测试
# 使用 SSO 进行身份验证的 API 测试
curl -X GET "https://[your-instance].ilucca.net/api/v3/users/me" \
-H "Authorization: lucca application=YOUR_API_KEY"
3. 移动端测试
卢卡移动应用支持 SSO:
- Figgo Mobile(iOS/Android)
- Timmi Mobile
- Lucca Mobile(统一应用)
故障排除
错误 "SSO 认证失败"
问题:SSO 认证失败
解决方案:
- 确保 SAML 的实体 ID 为
[appid] - 对于 OIDC,请检查 Discovery URL
- 确保电子邮件在卢卡中存在
- 查看日志:配置 → 认证日志
组未同步
问题:卢卡角色与 SmartLink 组不匹配
解决方案:
// 为组正确配置声明
{
"groups_claim": "groups",
"groups_mapping": {
"smartlink-rh": "ADMIN_RH",
"smartlink-managers": "MANAGER",
"smartlink-employees": "COLLABORATEUR"
}
}
错误 "用户未被授权访问此模块"
问题:SSO 用户无法访问某些模块
解决方案:
- 检查在卢卡中分配的许可证
- 检查用户角色的权限
- 确保 用户对模块有访问权限
管理员同步问题
问题:管理层关系未正确同步
解决方案:
<!-- 用于经理的 SAML 属性 -->
<saml:Attribute Name="manager_email">
<saml:AttributeValue>manager@entreprise.fr</saml:AttributeValue>
</saml:Attribute>
安全性
推荐配置
{
"security_settings": {
"enforce_sso": true,
"session_timeout": "8h",
"ip_filtering": {
"enabled": true,
"allowed_ips": ["10.0.0.0/8", "192.168.0.0/16"]
},
"api_security": {
"token_rotation": "30d",
"rate_limiting": true,
"audit_api_calls": true
},
"data_protection": {
"encryption_at_rest": true,
"anonymize_exports": true,
"gdpr_compliant": true
}
}
}
GDPR 合规性
卢卡符合 GDPR,具体包括:
- 在法国托管数据
- 右被遗忘
- 数据可携带性
- 敏感数据加密
- 完整审计跟踪
迁移现有用户
迁移脚本
import csv
import requests
from datetime import datetime
class LuccaSSOMigration:
def __init__(self, api_key, instance):
self.api_key = api_key
self.instance = instance
self.api_url = f"https://{instance}.ilucca.net/api/v3"
def migrate_users_to_sso(self, user_list_file):
"""批量迁移至 SSO"""
results = []
with open(user_list_file, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for user in reader:
try:
# 为用户启用 SSO
self.enable_sso_for_user(user['email'])
# 禁用密码验证
self.disable_password_auth(user['id'])
# 发送迁移电子邮件
self.send_migration_email(user['email'])
results.append({
'email': user['email'],
'status': 'success',
'timestamp': datetime.now()
})
except Exception as e:
results.append({
'email': user['email'],
'status': 'failed',
'error': str(e)
})
return results
def enable_sso_for_user(self, email):
# 通过卢卡 API 实现启用 SSO
pass