认证方法与流程
认证方法与流程
相关源文件
本章引用的主要源码文件:
api/controllers/console/auth/data_source_oauth.pyapi/controllers/console/auth/email_register.pyapi/controllers/console/auth/error.pyapi/controllers/console/auth/forgot_password.pyapi/controllers/console/auth/login.pyapi/controllers/console/auth/oauth.pyapi/controllers/console/explore/installed_app.pyapi/controllers/console/workspace/account.pyapi/controllers/console/workspace/members.pyapi/controllers/console/workspace/model_providers.pyapi/controllers/console/workspace/models.pyapi/controllers/console/workspace/plugin.pyapi/controllers/console/workspace/workspace.pyapi/controllers/web/forgot_password.pyapi/controllers/web/login.pyapi/controllers/web/passport.pyapi/controllers/web/wraps.pyapi/libs/oauth.pyapi/libs/oauth_data_source.pyapi/schedule/mail_clean_document_notify_task.pyapi/services/account_service.pyapi/services/entities/auth_entities.pyapi/services/webapp_auth_service.pyapi/templates/change_mail_confirm_old_template_zh-CN.htmlapi/templates/transfer_workspace_owner_confirm_template_en-US.htmlapi/templates/without-brand/transfer_workspace_owner_confirm_template_en-US.htmlapi/tests/unit_tests/libs/test_oauth_clients.pyapi/tests/unit_tests/services/test_account_service.pyweb/__tests__/embedded-user-id-auth.test.tsx- [web/app/(shareLayout)/chatbot/[token]/page.tsx](web/app/(shareLayout)/chatbot/[token]/page.tsx)
web/app/(shareLayout)/components/splash.tsx/components/splash.tsx)web/app/(shareLayout)/layout.tsx/layout.tsx)web/app/(shareLayout)/webapp-reset-password/check-code/page.tsx/webapp-reset-password/check-code/page.tsx)web/app/(shareLayout)/webapp-reset-password/page.tsx/webapp-reset-password/page.tsx)web/app/(shareLayout)/webapp-signin/check-code/page.tsx/webapp-signin/check-code/page.tsx)web/app/(shareLayout)/webapp-signin/components/external-member-sso-auth.tsx/webapp-signin/components/external-member-sso-auth.tsx)web/app/(shareLayout)/webapp-signin/components/mail-and-code-auth.tsx/webapp-signin/components/mail-and-code-auth.tsx)web/app/(shareLayout)/webapp-signin/components/mail-and-password-auth.tsx/webapp-signin/components/mail-and-password-auth.tsx)web/app/(shareLayout)/webapp-signin/components/sso-auth.tsx/webapp-signin/components/sso-auth.tsx)web/app/(shareLayout)/webapp-signin/page.tsx/webapp-signin/page.tsx)web/app/account/oauth/authorize/page.tsxweb/app/components/app-initializer.tsxweb/app/components/app/annotation/batch-add-annotation-modal/index.tsxweb/app/components/base/app-unavailable.tsxweb/app/components/base/emoji-picker/index.tsxweb/app/components/base/input/index.tsxweb/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/__tests__/index.spec.tsxweb/app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/__tests__/index.spec.tsxweb/app/components/header/account-setting/members-page/__tests__/index.spec.tsxweb/app/components/header/account-setting/members-page/index.tsxweb/app/components/header/account-setting/members-page/operation/__tests__/index.spec.tsxweb/app/components/header/account-setting/members-page/operation/index.tsxweb/app/components/share/utils.tsweb/app/reset-password/check-code/page.tsxweb/app/reset-password/page.tsxweb/app/signin/check-code/page.tsxweb/app/signin/components/mail-and-code-auth.tsxweb/app/signin/components/mail-and-password-auth.tsxweb/app/signin/normal-form.tsxweb/app/signin/split.tsxweb/app/signin/utils/post-login-redirect.tsweb/app/signup/check-code/page.tsxweb/app/signup/components/input-mail.spec.tsxweb/app/signup/components/input-mail.tsxweb/app/signup/layout.tsxweb/app/signup/page.tsxweb/app/signup/set-password/page.tsxweb/context/web-app-context.tsxweb/hooks/use-app-favicon.tsweb/service/base.tsweb/service/share.tsweb/service/sso.tsweb/service/use-share.spec.tsxweb/service/use-share.tsweb/service/webapp-auth.tsweb/utils/emoji.ts
目的与范围
本文档描述了 Dify 中可用的认证方法及其技术实现流程。涵盖控制台认证(邮箱/密码、OAuth、邮箱验证码)、WebApp 认证(终端用户访问)和 API 认证(程序化访问)。本页详细介绍了令牌管理生命周期,包括访问令牌、刷新令牌和 CSRF 令牌,以及密码哈希和速率限制等底层安全机制。
认证架构总览
Dify 使用多层认证系统来处理不同的用户角色和访问模式。核心逻辑位于 AccountService 中,并通过 Flask 装饰器和中间件来强制执行。
用户认证层与代码实体
下图将高级认证流程映射到具体的后端控制器和服务类。
来源: api/services/account_service.py:115-160, api/controllers/console/auth/login.py:93-168, api/libs/helper.py:31-33, api/controllers/console/auth/oauth.py:82-106
控制台认证流程
邮箱/密码认证
标准登录流程包括凭证校验、账户状态检查以及 TokenPair 的签发。
实现细节:
- 认证:
AccountService.authenticate会验证邮箱和密码是否与数据库匹配api/services/account_service.py:194-222。 - 密码哈希: 使用 PBKDF2-HMAC-SHA256 算法,并通过
libs.password为每个用户生成独立的盐值api/libs/password.py:1-40。 - 令牌签发:
AccountService.login会生成一个 JWT 访问令牌、一个刷新令牌和一个 CSRF 令牌api/services/account_service.py:438-452。 - 速率限制: 失败的登录尝试会通过
AccountService.add_login_error_rate_limit记录在 Redis 中api/controllers/console/auth/login.py:142。
登录与令牌管理序列:
来源: api/services/account_service.py:438-452, api/controllers/console/auth/login.py:164-166, api/libs/password.py:1-40, api/services/account_service.py:150-155
OAuth 认证(GitHub/Google)
OAuth 2.0 流程允许用户通过第三方提供商登录。Dify 处理重定向、令牌交换和账户映射。
- 发起:
OAuthLogin.get将用户重定向到提供商的授权 URLapi/controllers/console/auth/oauth.py:82-106。 - 回调:
OAuthCallback.get接收授权码,将其交换为访问令牌,并获取用户信息api/controllers/console/auth/oauth.py:109-147。 - 账户生成: 如果用户不存在,
_generate_account会创建一个新的Account和Tenantapi/controllers/console/auth/oauth.py:165-172。 - 集成映射: 使用
AccountIntegrate模型将 Dify 账户与 OAuth 身份关联起来api/models/account.py:284-300。
来源: api/controllers/console/auth/oauth.py:82-172, api/libs/oauth.py:1-150, api/services/account_service.py:373-397
邮箱验证码登录(无密码)
此流程使用 TokenManager 来处理短时效的验证码。
- 请求验证码:
EmailCodeLoginSendEmailApi触发send_email_code_login_mail_taskapi/controllers/console/auth/login.py:215-259。 - 令牌生成: 会生成一个 6 位数字验证码,并通过
TokenManager.generate_token将其存储在 Redis 中,有效期为 10 分钟api/libs/helper.py:358-385。 - 校验:
EmailCodeLoginApi验证验证码,如果有效则签发会话api/controllers/console/auth/login.py:269-313。
来源: api/controllers/console/auth/login.py:215-313, api/libs/helper.py:358-433, api/services/account_service.py:765-812
令牌管理与安全
令牌生命周期与存储
Dify 为控制台会话管理三种主要的令牌类型:
| 令牌类型 | 用途 | 存储方式 | 生命周期(默认值) |
|---|---|---|---|
| 访问令牌 | 用于 API 认证的 JWT | HTTP-only Cookie | 30 分钟 |
| 刷新令牌 | 续期访问令牌 | Redis + HTTP-only Cookie | REFRESH_TOKEN_EXPIRY(30 天) |
| CSRF 令牌 | 防止 CSRF 攻击 | 非 HTTP-only Cookie | 会话期间 |
刷新令牌逻辑: 刷新令牌使用两个键存储在 Redis 中,以实现双向查找:
refresh_token:{token}->account_idapi/services/account_service.py:142-143account_refresh_token:{account_id}->refresh_tokenapi/services/account_service.py:146-147
来源: api/services/account_service.py:104-108, api/libs/token.py:1-100, api/services/account_service.py:150-155
CSRF 保护
所有状态变更请求都会强制执行 CSRF 保护。令牌通过 generate_csrf_token 生成,并作为 Cookie 发送给客户端 api/libs/token.py:131-133。前端(Web)会读取此 Cookie,并将其包含在请求的 X-CSRF-Token 请求头中 web/service/base.ts:32。
来源: api/libs/token.py:131-133, web/service/base.ts:31-35
WebApp 与 API 认证
WebApp Passport 流程
对于已发布的 WebApp(聊天机器人等),Dify 使用 "Passport" 机制来认证终端用户。
- 提取:
getWebAppPassport从请求头中获取令牌web/service/base.ts:37。 - 校验:
PassportService会根据App和EndUser模型验证 passportapi/libs/passport.py:1-50。 - SSO 登录: 如果配置了 SSO,WebApp 可能需要 SSO 登录
web/service/base.ts:167-179。
来源: web/service/base.ts:37, api/libs/passport.py:1-50, web/service/base.ts:167-179
服务 API 密钥认证
通过服务 API 进行的程序化访问使用 API 密钥(Bearer 令牌)。
- 校验:
wraps.py中的装饰器会在ApiToken表中查找令牌api/controllers/service_api/wraps.py:50-127。 - 租户上下文: 校验成功后,系统会为请求设置租户上下文
api/controllers/service_api/wraps.py:122-124。
来源: api/controllers/service_api/wraps.py:50-127, api/models/model.py:1-100
账户生命周期安全
账户删除与冻结
账户删除受验证码流程保护。
- 验证:
send_account_deletion_verification_code会向用户邮箱发送验证码api/services/account_service.py:335-340。 - 任务执行:
delete_account_task会异步触发,以清理关联的资源api/services/account_service.py:66。 - 冻结期: 在云版本中,
BillingService.is_email_in_freeze会阻止同一邮箱在冷却期内重新注册api/controllers/console/auth/login.py:108-110。
来源: api/services/account_service.py:335-370, api/controllers/console/auth/login.py:108-110, api/services/billing_service.py:1-100
速率限制
Dify 使用 RateLimiter 类对敏感操作实施严格的速率限制。
- 登录限制:
LOGIN_MAX_ERROR_LIMITS = 5api/services/account_service.py:135。 - 邮箱限制: 针对注册、密码重置和验证码登录分别设置了独立的限制器
api/services/account_service.py:124-133。 - IP 限制: 如果某个 IP 超过发送阈值,会抛出
EmailSendIpLimitError异常api/controllers/console/auth/login.py:26。
来源: api/services/account_service.py:124-135, api/libs/helper.py:31-33