Files
SnapOtter/apps/docs/th/guide/oidc.md
T
SnapOtterandGitHub 4963ab3bbd feat(docs-i18n): translate all documentation into 20 languages
All 181 docs markdown files translated into 20 languages (apps/docs/<locale>/**). Companion to the i18n code PR; admin-merged because the file count exceeds GitHub's per-PR CI trigger limit. Validated by pnpm i18n:check (all surfaces, 0 stale/missing) and a clean all-locale docs build.
2026-07-11 13:52:47 +08:00

171 lines
14 KiB
Markdown

---
description: "ตั้งค่า Single Sign-On ด้วย OpenID Connect คู่มือทีละขั้นตอนสำหรับ Keycloak, Authentik, Google และผู้ให้บริการ OIDC อื่น ๆ"
i18n_source_hash: 4296343b3cc5
i18n_provenance: human
i18n_output_hash: cf303e97a8f0
---
# OIDC / Single Sign-On {#oidc-single-sign-on}
SnapOtter รองรับ OpenID Connect (OIDC) สำหรับ single sign-on ผู้ใช้สามารถเข้าสู่ระบบด้วยผู้ให้บริการข้อมูลประจำตัวภายนอกอย่าง Keycloak, Authentik หรือ Google แทน (หรือควบคู่ไปกับ) การยืนยันตัวตนด้วยชื่อผู้ใช้/รหัสผ่านในเครื่อง
::: tip ดูเพิ่มเติม
[SAML SSO](/th/guide/saml) | [SCIM Provisioning](/th/guide/scim) | [ผู้ใช้ บทบาท และสิทธิ์](/th/guide/users-roles)
:::
## เริ่มต้นอย่างรวดเร็ว {#quick-start}
เพิ่มตัวแปรสภาพแวดล้อมเหล่านี้ลงใน `docker-compose.yml` ของคุณ:
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
environment:
EXTERNAL_URL: "https://photos.example.com"
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"
```
redirect URI สำหรับผู้ให้บริการของคุณจะเป็นแบบนี้เสมอ:
```
${EXTERNAL_URL}/api/auth/oidc/callback
```
ตัวอย่างเช่น หาก `EXTERNAL_URL` คือ `https://photos.example.com` ให้กำหนด redirect URI ของผู้ให้บริการเป็น `https://photos.example.com/api/auth/oidc/callback`
## เอกสารอ้างอิงการกำหนดค่า {#configuration-reference}
| ตัวแปร | ค่าเริ่มต้น | คำอธิบาย |
|---|---|---|
| `OIDC_ENABLED` | `false` | เปิดใช้งานการเข้าสู่ระบบ OIDC ปุ่ม "Sign in with SSO" จะปรากฏบนหน้าเข้าสู่ระบบ |
| `OIDC_ISSUER_URL` | | URL ผู้ออก (issuer) ของผู้ให้บริการ ต้องรองรับ OIDC Discovery (`/.well-known/openid-configuration`) |
| `OIDC_CLIENT_ID` | | OAuth client ID ที่ลงทะเบียนกับผู้ให้บริการของคุณ |
| `OIDC_CLIENT_SECRET` | | OAuth client secret |
| `OIDC_SCOPES` | `openid profile email` | รายการ scope ที่คั่นด้วยช่องว่างเพื่อร้องขอ |
| `OIDC_AUTO_CREATE_USERS` | `true` | สร้างบัญชีผู้ใช้ในเครื่องโดยอัตโนมัติเมื่อเข้าสู่ระบบ OIDC ครั้งแรก |
| `OIDC_DEFAULT_ROLE` | `user` | บทบาทที่กำหนดให้ผู้ใช้ OIDC ที่สร้างอัตโนมัติ หนึ่งใน `admin`, `editor` หรือ `user` |
| `OIDC_AUTO_LINK_USERS` | `false` | เชื่อมโยงข้อมูลประจำตัว OIDC กับผู้ใช้ในเครื่องที่มีอยู่หากที่อยู่อีเมลตรงกัน |
| `OIDC_PROVIDER_NAME` | | ชื่อที่แสดงบนปุ่มเข้าสู่ระบบ (เช่น "Keycloak", "Google") หากว่างเปล่า ปุ่มจะแสดง "SSO" |
| `OIDC_CLOCK_TOLERANCE` | `30` | ความคลาดเคลื่อนของนาฬิกาที่ยอมรับได้เป็นวินาทีสำหรับการตรวจสอบ token |
| `OIDC_USERNAME_CLAIM` | `preferred_username` | claim ของ ID token ที่ใช้เป็นชื่อผู้ใช้สำหรับบัญชีใหม่ |
| `EXTERNAL_URL` | | URL สาธารณะที่เข้าถึง SnapOtter ได้ จำเป็นสำหรับ OIDC เพื่อสร้าง redirect URI ที่ถูกต้อง |
| `COOKIE_SECRET` | สร้างอัตโนมัติ | secret สำหรับเซ็นชื่อคุกกี้เซสชัน ตั้งค่านี้อย่างชัดเจนเมื่อรันหลาย replica |
## คู่มือผู้ให้บริการ {#provider-guides}
### Keycloak {#keycloak}
1. สร้าง realm ใหม่ (หรือใช้ที่มีอยู่)
2. ไปที่ **Clients** และสร้าง client ใหม่:
- **Client ID**: `snapotter`
- **Client authentication**: เปิด (confidential)
- **Authentication flow**: Standard flow (Authorization Code)
3. ใต้แท็บ **Settings** ของ client ให้ตั้งค่า **Valid redirect URIs** เป็น callback URL ของคุณ (เช่น `https://photos.example.com/api/auth/oidc/callback`)
4. คัดลอก **Client secret** จากแท็บ **Credentials**
5. ตั้งค่า `OIDC_ISSUER_URL` เป็น `https://keycloak.example.com/realms/your-realm`
### Authentik {#authentik}
1. ในหน้าจอผู้ดูแลระบบ ไปที่ **Applications > Providers** และสร้าง **OAuth2/OpenID Provider** ใหม่
- **Client type**: Confidential
- **Redirect URIs**: callback URL ของคุณ
- **Signing key**: เลือกคีย์ที่มีอยู่หรือสร้างขึ้นใหม่
2. สร้าง **Application** และเชื่อมโยงกับ provider
3. คัดลอก **Client ID** และ **Client Secret** จากการตั้งค่า provider
4. ตั้งค่า `OIDC_ISSUER_URL` เป็น `https://authentik.example.com/application/o/snapotter/` (เครื่องหมายทับท้ายมีความสำคัญ)
### Google {#google}
1. ไปที่ [Google Cloud Console](https://console.cloud.google.com/)
2. สร้างโปรเจกต์ (หรือเลือกที่มีอยู่)
3. ไปที่ **APIs & Services > OAuth consent screen** และกำหนดค่า
4. ไปที่ **APIs & Services > Credentials** และสร้าง **OAuth 2.0 Client ID**:
- **Application type**: Web application
- **Authorized redirect URIs**: callback URL ของคุณ
5. คัดลอก **Client ID** และ **Client secret**
6. ตั้งค่า `OIDC_ISSUER_URL` เป็น `https://accounts.google.com`
7. ตั้งค่า `OIDC_USERNAME_CLAIM` เป็น `email` (Google ไม่ให้ `preferred_username`)
## การจัดสรรผู้ใช้ {#user-provisioning}
### สร้างอัตโนมัติ {#auto-create}
เมื่อ `OIDC_AUTO_CREATE_USERS` เป็น `true` (ค่าเริ่มต้น) บัญชีผู้ใช้ในเครื่องจะถูกสร้างขึ้นในครั้งแรกที่มีคนเข้าสู่ระบบผ่าน OIDC ชื่อผู้ใช้จะดึงมาจาก claim ที่ระบุโดย `OIDC_USERNAME_CLAIM` และบทบาทจะถูกตั้งเป็น `OIDC_DEFAULT_ROLE`
หากเกิดชื่อผู้ใช้ซ้ำกัน จะมีการต่อท้ายด้วยตัวเลข (เช่น `jane` กลายเป็น `jane_2`)
### เชื่อมโยงอัตโนมัติ {#auto-link}
เมื่อ `OIDC_AUTO_LINK_USERS` เป็น `true` SnapOtter จะเชื่อมโยงข้อมูลประจำตัว OIDC กับบัญชีในเครื่องที่มีอยู่หากที่อยู่อีเมลตรงกัน สิ่งนี้มีประโยชน์เมื่อคุณมีบัญชีผู้ใช้ที่สร้างไว้ล่วงหน้าและต้องการให้พวกเขาเริ่มใช้ SSO โดยไม่สูญเสียข้อมูล
::: warning
เปิดใช้งานการเชื่อมโยงอัตโนมัติเฉพาะเมื่อคุณไว้ใจผู้ให้บริการ OIDC ของคุณในการตรวจสอบที่อยู่อีเมล อีเมลที่ไม่ได้รับการยืนยันอาจทำให้ใครบางคนเข้ายึดบัญชีของผู้ใช้อื่นได้
:::
### การปิดการเข้าสู่ระบบในเครื่อง {#disabling-local-login}
OIDC ไม่ปิดการเข้าสู่ระบบด้วยชื่อผู้ใช้/รหัสผ่านในเครื่อง ทั้งสองวิธียังคงใช้งานได้ ผู้ดูแลระบบยังสามารถเข้าสู่ระบบด้วยข้อมูลประจำตัวในเครื่องได้หากผู้ให้บริการ OIDC ไม่สามารถเข้าถึงได้
## ใบรับรองที่เซ็นด้วยตนเอง {#self-signed-certificates}
หากผู้ให้บริการ OIDC ของคุณใช้ใบรับรองที่เซ็นด้วยตนเองหรือใบรับรอง CA ส่วนตัว ให้ mount CA bundle เข้าไปในคอนเทนเนอร์และชี้ `NODE_EXTRA_CA_CERTS` ไปที่มัน:
```yaml
services:
SnapOtter:
image: snapotter/snapotter:latest
volumes:
- ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
environment:
NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
OIDC_ENABLED: "true"
OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
OIDC_CLIENT_ID: "snapotter"
OIDC_CLIENT_SECRET: "your-secret-here"
```
::: danger
อย่าตั้งค่า `NODE_TLS_REJECT_UNAUTHORIZED=0` สิ่งนี้จะปิดการตรวจสอบ TLS ทั้งหมดและเป็นความเสี่ยงด้านความปลอดภัย
:::
## การแก้ไขปัญหา {#troubleshooting}
### redirect URI ไม่ตรงกัน {#redirect-uri-mismatch}
ข้อผิดพลาดที่พบบ่อยที่สุด ตรวจสอบความแตกต่างเหล่านี้ระหว่างสิ่งที่ผู้ให้บริการคาดหวังกับสิ่งที่ SnapOtter ส่ง:
- `http` กับ `https` scheme ต้องตรงกันทุกประการ
- เครื่องหมายทับท้าย ผู้ให้บริการบางรายเข้มงวดเรื่องนี้
- หมายเลขพอร์ต ระบุพอร์ตหากไม่ใช่ค่ามาตรฐาน
- Path ต้องเป็น `/api/auth/oidc/callback`
ตรวจสอบ `EXTERNAL_URL` อีกครั้ง มันต้องตรงกับ URL ที่ผู้ใช้พิมพ์ในเบราว์เซอร์
### UNABLE_TO_VERIFY_LEAF_SIGNATURE {#unable-to-verify-leaf-signature}
ผู้ให้บริการ OIDC กำลังใช้ใบรับรองที่ Node.js ไม่ไว้ใจ ดู [ใบรับรองที่เซ็นด้วยตนเอง](#self-signed-certificates) ด้านบน
### ข้อผิดพลาดความคลาดเคลื่อนของนาฬิกา {#clock-skew-errors}
หากนาฬิกาเซิร์ฟเวอร์และนาฬิกาผู้ให้บริการ OIDC ไม่ตรงกัน การตรวจสอบ token อาจล้มเหลว เพิ่มค่า `OIDC_CLOCK_TOLERANCE` (ค่าเริ่มต้นคือ 30 วินาที) วิธีแก้ที่ดีกว่าคือรัน NTP บนทั้งสองเครื่อง
### "OIDC provider unreachable" {#oidc-provider-unreachable}
SnapOtter ดึงเอกสาร discovery ของผู้ให้บริการเมื่อเริ่มต้นและระหว่างการเข้าสู่ระบบ ตรวจสอบ:
- การแปลง DNS จากภายในคอนเทนเนอร์ Docker (`docker exec snapotter nslookup auth.example.com`)
- กฎไฟร์วอลล์ระหว่างคอนเทนเนอร์และผู้ให้บริการ
- ค่า `OIDC_ISSUER_URL` ต้องเข้าถึงได้จากเซิร์ฟเวอร์ ไม่ใช่แค่จากเบราว์เซอร์ของคุณ
### claim ที่ขาดหายไป {#missing-claims}
หากชื่อผู้ใช้หรืออีเมลว่างเปล่าหลังจากเข้าสู่ระบบ ผู้ให้บริการของคุณอาจไม่ได้ส่ง claim ที่คาดหวังกลับมา ตรวจสอบ:
- scope ที่กำหนดค่าใน `OIDC_SCOPES` มี `profile` และ `email`
- ผู้ให้บริการถูกกำหนดค่าให้รวม claim ที่ระบุใน `OIDC_USERNAME_CLAIM` ไว้ใน ID token
- ผู้ให้บริการบางรายต้องการการกำหนดค่า mapper/scope อย่างชัดเจนเพื่อปล่อย claim