Skip to content

SSO 與 OAuth 認證

配置 Google OAuth、GitHub OAuth 和通用 OIDC 以實現安全的生產環境認證。

v2.3.0 新增

預設情況下,Potato 使用簡單的使用者名稱登入,標註者輸入任意使用者名稱即可登入。這對於本地開發和小型項目來說很方便,但生產環境的部署需要適當的認證來防止未授權訪問、確保標註者身份並符合機構要求。

Potato 2.3 增加了對三種認證方法的支援:

  1. Google OAuth -- 使用 Google 賬戶登入,可選域名限制
  2. GitHub OAuth -- 使用 GitHub 賬戶登入,可選組織限制
  3. 通用 OIDC -- 連線任何 OpenID Connect 提供商(Okta、Azure AD、Auth0、Keycloak 等)

所有方法都可以與 Potato 現有的使用者名稱登入結合使用,實現混合模式配置。

Google OAuth

前提條件

  1. Google Cloud Console 中建立項目
  2. 啟用 "Google Identity" API
  3. 建立 OAuth 2.0 憑據(Web 應用類型)
  4. 將你的 Potato 伺服器 URL 新增到"已授權的重定向 URI":https://your-server.com/auth/google/callback

配置

yaml
authentication:
  method: google_oauth
 
  google_oauth:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/google/callback"
 
    # Optional: restrict to specific domain(s)
    allowed_domains:
      - "umich.edu"
      - "research-lab.org"
 
    # Optional: auto-register new users on first login
    auto_register: true
 
    # Optional: map Google profile fields to Potato user fields
    field_mapping:
      username: email            # use email as Potato username
      display_name: name         # show Google display name

域名限制

當設定 allowed_domains 時,只有來自這些域名的電子郵件地址的使用者才能登入。其他使用者會看到錯誤訊息:

yaml
authentication:
  method: google_oauth
  google_oauth:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
    allowed_domains:
      - "umich.edu"
    domain_error_message: "This annotation task is restricted to University of Michigan accounts."

GitHub OAuth

前提條件

  1. 前往 GitHub Settings > Developer settings > OAuth Apps > New OAuth App
  2. 將 "Authorization callback URL" 設定為 https://your-server.com/auth/github/callback
  3. 記下你的 Client ID 並生成 Client Secret

配置

yaml
authentication:
  method: github_oauth
 
  github_oauth:
    client_id: ${GITHUB_CLIENT_ID}
    client_secret: ${GITHUB_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/github/callback"
 
    # Optional: restrict to members of specific GitHub organizations
    allowed_organizations:
      - "my-research-lab"
      - "university-nlp-group"
 
    # Optional: restrict to specific teams within an organization
    allowed_teams:
      - "my-research-lab/annotators"
 
    # Scopes to request
    scopes:
      - "read:user"
      - "read:org"             # needed for organization restriction
 
    auto_register: true
 
    field_mapping:
      username: login            # GitHub username
      display_name: name

組織限制

GitHub OAuth 可以將訪問限制為特定組織的成員。這需要 read:org 許可權範圍:

yaml
authentication:
  method: github_oauth
  github_oauth:
    client_id: ${GITHUB_CLIENT_ID}
    client_secret: ${GITHUB_CLIENT_SECRET}
    allowed_organizations:
      - "my-research-lab"
    scopes:
      - "read:user"
      - "read:org"
    org_error_message: "You must be a member of the my-research-lab GitHub organization."

通用 OIDC

對於企業 SSO 提供商(Okta、Azure AD、Auth0、Keycloak 等),使用通用 OpenID Connect 整合。

配置

yaml
authentication:
  method: oidc
 
  oidc:
    # Discovery URL (provider's .well-known endpoint)
    discovery_url: "https://accounts.example.com/.well-known/openid-configuration"
 
    # Or specify endpoints manually
    # authorization_endpoint: "https://accounts.example.com/authorize"
    # token_endpoint: "https://accounts.example.com/token"
    # userinfo_endpoint: "https://accounts.example.com/userinfo"
    # jwks_uri: "https://accounts.example.com/.well-known/jwks.json"
 
    client_id: ${OIDC_CLIENT_ID}
    client_secret: ${OIDC_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/oidc/callback"
 
    scopes:
      - "openid"
      - "profile"
      - "email"
 
    auto_register: true
 
    field_mapping:
      username: preferred_username
      display_name: name
      email: email

Azure AD 示例

yaml
authentication:
  method: oidc
 
  oidc:
    discovery_url: "https://login.microsoftonline.com/${AZURE_TENANT_ID}/v2.0/.well-known/openid-configuration"
    client_id: ${AZURE_CLIENT_ID}
    client_secret: ${AZURE_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/oidc/callback"
    scopes:
      - "openid"
      - "profile"
      - "email"
    auto_register: true
    field_mapping:
      username: preferred_username
      display_name: name

Okta 示例

yaml
authentication:
  method: oidc
 
  oidc:
    discovery_url: "https://your-org.okta.com/.well-known/openid-configuration"
    client_id: ${OKTA_CLIENT_ID}
    client_secret: ${OKTA_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/oidc/callback"
    scopes:
      - "openid"
      - "profile"
      - "email"
      - "groups"               # request group membership
    auto_register: true
 
    # Restrict to specific groups
    allowed_groups:
      - "annotation-team"
 
    field_mapping:
      username: preferred_username
      display_name: name
      groups: groups

Keycloak 示例

yaml
authentication:
  method: oidc
 
  oidc:
    discovery_url: "https://keycloak.example.com/realms/annotation/.well-known/openid-configuration"
    client_id: ${KEYCLOAK_CLIENT_ID}
    client_secret: ${KEYCLOAK_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/oidc/callback"
    scopes:
      - "openid"
      - "profile"
      - "email"
    auto_register: true
    field_mapping:
      username: preferred_username
      display_name: name

域名限制

所有 OAuth 方法都支援基於電子郵件地址的域名限制。當你希望允許特定機構的任何賬戶時,這很有用:

yaml
authentication:
  method: google_oauth          # or github_oauth, oidc
 
  domain_restriction:
    enabled: true
    allowed_domains:
      - "umich.edu"
      - "stanford.edu"
    error_message: "Access is restricted to university accounts."

對於包含 email 宣告的 OIDC 提供商,域名限制會自動生效。對於不包含電子郵件的提供商,你可能需要顯式請求 email 許可權範圍。

自動註冊

預設情況下,使用者必須在 Potato 中預註冊才能進行標註。啟用 auto_register: true 後,任何成功認證的使用者在首次登入時會自動在 Potato 中建立。

yaml
authentication:
  auto_register: true
  auto_register_role: annotator   # annotator or admin

如需預先批准特定使用者並阻止其他人:

yaml
authentication:
  auto_register: false
  allowed_users:
    - "researcher@umich.edu"
    - "student1@umich.edu"
    - "student2@umich.edu"
  user_not_found_message: "Your account has not been approved. Contact the project administrator."

混合模式

你可以同時啟用多種認證方法。登入頁面為每種啟用的方法顯示按鈕,並可選顯示使用者名稱欄位。

yaml
authentication:
  methods:
    - google_oauth
    - github_oauth
    - username                   # keep simple username login as fallback
 
  google_oauth:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/google/callback"
 
  github_oauth:
    client_id: ${GITHUB_CLIENT_ID}
    client_secret: ${GITHUB_CLIENT_SECRET}
    redirect_uri: "https://your-server.com/auth/github/callback"
 
  # Username login settings
  username:
    enabled: true
    require_password: true       # require a password for username login
    password_file: "auth/passwords.yaml"

混合模式在遷移期間很有用:在使用者名稱登入旁邊啟用 OAuth,然後在所有標註者關聯了 OAuth 賬戶後停用使用者名稱登入。

會話管理

為已認證使用者配置會話行為:

yaml
authentication:
  session:
    lifetime_hours: 24           # session duration
    refresh: true                # refresh session on activity
    cookie_secure: true          # require HTTPS for cookies
    cookie_samesite: "Lax"       # SameSite cookie attribute

管理員認證

管理員賬戶可以使用相同的 OAuth 流程或單獨的認證方法:

yaml
authentication:
  method: google_oauth
  google_oauth:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
 
  admin:
    # Admins must match these emails
    admin_emails:
      - "pi@umich.edu"
      - "lead-ra@umich.edu"
 
    # Or use a separate API key for admin access
    api_key: ${ADMIN_API_KEY}

HTTPS 要求

OAuth 提供商在生產環境中要求重定向 URI 使用 HTTPS。對於本地開發,可以使用 HTTP 和 localhost:

yaml
# Development (HTTP allowed)
authentication:
  google_oauth:
    redirect_uri: "http://localhost:8000/auth/google/callback"
 
# Production (HTTPS required)
authentication:
  google_oauth:
    redirect_uri: "https://annotation.example.com/auth/google/callback"

對於反向代理(nginx、Caddy)後面的生產環境部署,確保代理轉發正確的 X-Forwarded-Proto 頭:

nginx
# nginx example
location / {
    proxy_pass http://localhost:8000;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
}

完整示例

完整的生產環境認證配置,包含 Google OAuth、域名限制和管理員 API 金鑰:

yaml
task_name: "Annotation Project"
task_dir: "."
 
authentication:
  method: google_oauth
 
  google_oauth:
    client_id: ${GOOGLE_CLIENT_ID}
    client_secret: ${GOOGLE_CLIENT_SECRET}
    redirect_uri: "https://annotation.umich.edu/auth/google/callback"
    allowed_domains:
      - "umich.edu"
    auto_register: true
    field_mapping:
      username: email
      display_name: name
 
  session:
    lifetime_hours: 48
    cookie_secure: true
 
  admin:
    admin_emails:
      - "pi@umich.edu"
    api_key: ${ADMIN_API_KEY}
 
data_files:
  - "data/instances.jsonl"
 
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    labels: [Positive, Neutral, Negative]
 
output_annotation_dir: "output/"
output_annotation_format: "jsonl"

延伸閱讀

有關實現詳情,請參閱源文件