SSO холбоос: нэг суулгац нөгөөгөө таниулах
Gerege Nexus эхнээсээ identity provider байсан: OAuth2 authorization server
бөгөөд OpenID Connect provider (backend/internal/platform/ssoprovider).
Түүн дээр бүртгэлтэй апп, гадаад систем нь энэ платформоор дамжуулан хүнийг
танидаг.
Одоо нөгөө хагас нь бий: суулгац өөрөө өөр провайдерийн клиент байж болно
(backend/internal/platform/ssoclient). Хоёр хагас нь бие биеэсээ хамааралгүй.
Нэг суулгац дараах гурван байдлын аль нэгээр ажиллана:
| Тохиргоо | Юу болох вэ |
|---|---|
SSO_CLIENT_ISSUER хоосон |
Урьдын адил. Суулгац хүнийг өөрөө таниулж, өөрөө identity тарааж өгнө. |
SSO_CLIENT_ISSUER тохируулсан |
Суулгац хүнийг өөрөө танихаа болино — нэвтрэлт провайдер дээр болно. Апп-уудад identity тараах чадвар нь хэвээр. |
| Хоёулаа | Аймгийн суулгац улсын нэгдсэн рүү дээшээ холбогдож, өөрөө өөрийн дээр суусан аппуудад identity өгнө. Энэ хэлбэрийг зорьж хийсэн. |
Клиент болгож тохируулах
Хамгийн бага тохиргоо нь хоёр хувьсагч:
SSO_CLIENT_ISSUER=https://nexus.gerege.mn
SSO_CLIENT_ID=aimag-office
Бусад нь заавал биш:
| Хувьсагч | Утга |
|---|---|
SSO_CLIENT_SECRET |
Хоосон бол public клиент — солилцоог PKCE дангаараа баталгаажуулна. Суулгац бол сервер тул нууц үг барьж чадна; провайдер олгосон бол тавь. |
SSO_CLIENT_PROVIDER_NAME |
Нэвтрэх дэлгэц дээр провайдерийг юу гэж нэрлэх. Хоосон бол issuer-ийн host. |
SSO_CLIENT_SCOPES |
Өгөгдмөл openid profile email. Жагсаалтад байхгүй байсан ч openid нэмэгдэнэ: түүнгүйгээр id_token огт ирэхгүй. |
SSO_CLIENT_REDIRECT_URI |
Өгөгдмөл ${SSO_ISSUER}/api/v1/auth/sso/callback. Хөгжүүлэлтэд API :8080, вэб :3000 тул гараар зааж өгнө. |
SSO_CLIENT_POST_LOGOUT_REDIRECT_URI |
Гарсны дараа хаана буцаж очих. Өгөгдмөл ${SSO_ISSUER}/. |
SSO_CLIENT_TENANT |
Провайдерийн баталгаажуулсан ч энд бүртгэлгүй хүнийг ямар байгууллагад үүсгэх. Хоосон бол хэнийг ч үүсгэхгүй — танихгүй хүнийг татгалзана. |
SSO_CLIENT_LOCAL_LOGIN |
true бол эндэх нууц үг, eID нэвтрэлт хамт ажиллана. Өгөгдмөл false. Энэ бол провайдер унасан үед буцаж орох баталгаатай зам. |
Production дээр SSO_CLIENT_ISSUER заавал HTTPS байх ба SSO_CLIENT_ID
шаардлагатай — эс бөгөөс сервер эхлэхээсээ өмнө татгалзана. Loopback дээр
http:// зөвшөөрөгдөнө: нэг машин дээр хоёр суулгацыг бие бие рүү нь чиглүүлж
турших замыг нээлттэй байлгах гэсэн санаа.
Провайдер дээр юу бүртгүүлэх вэ
Провайдер нь өөр Gerege Nexus бол Хөгжүүлэгч → Аппликейшн дотроос клиент үүсгээд:
- redirect_uris —
https://<клиент-суулгац>/api/v1/auth/sso/callback - post_logout_redirect_uris —
https://<клиент-суулгац>/ - grant_types —
authorization_code(шаардлагатай болrefresh_token) - scopes — наад зах нь
openid, дээрээс ньprofile,email
Хоёр хаягийн host нь провайдерийн OAUTH_REDIRECT_HOSTS жагсаалтад байх
ёстой. Тэр жагсаалт нь дэд домэйныг өвлүүлдэггүй, яг таарч байж болно.
Ажиллах урсгал
Нэвтрэх
- Хүн клиент суулгац дээр
/loginдээр ирнэ. Дэлгэц/api/v1/auth/sso/config-оос энэ суулгац хэрхэн нэвтрүүлдгийг асууна. - Холбоостой бол дэлгэц юу ч асуухгүй — хөтчийг
/api/v1/auth/sso/startруу илгээнэ. startнь PKCE verifier,state,nonceүүсгээд гурвуулангийнх нь хамт очих газрыг (next) богино хугацааны HttpOnly cookie-д хийж, провайдерийн authorization endpoint руу чиглүүлнэ. Тэр хаягийг провайдерийн өөрийнх нь discovery баримтаас авна, хүсэлтээс биш.- Провайдер дээр хүн нэвтэрч (эсвэл аль хэдийн нэвтэрсэн бол шууд) кодтой
буцаж
/api/v1/auth/sso/callbackдээр ирнэ. - Callback нь cookie-н
state-тэй тулгаж, кодыг token endpoint дээр солиод ирсэнid_token-ийг провайдерийн JWKS-ээр шалгана: RS256 гэдгийг, гарын үсгийг,iss,aud,azp,exp,iat,nonceбүгдийг. - Баталгаажсан хүнийг эндэх бүртгэлтэй холбож (доор үзнэ үү), session үүсгэж,
nextрүү буцаана.
Гарах
- Хөтөч
/api/v1/auth/logoutдуудна. Эндэх session тэр дороо хүчингүй болно. - Хариу нь
end_session_urlавчирна — провайдерийнend_session_endpointдээрclient_id,id_token_hint,post_logout_redirect_uri-тай. - Хөтөч тийш очно. Провайдер өөрийн session-ээ хааж, бүртгэлтэй
post_logout_redirect_uriдээр буцаана.
Гурав дахь алхам байхгүй бол хүн "гарлаа" гээд "нэвтрэх" дархад шууд буцаж ордог — өөрөөр хэлбэл гараагүй.
Хэн болохыг эндэх бүртгэлтэй холбох
Түлхүүр нь (issuer, subject), и-мэйл биш. И-мэйл бол провайдер өөрчилж
болох шошго: гарсан ажилтны хаягийг өөр хүнд өгвөл тэр хүн түүний бүртгэлийг
өвлөнө. subject бол провайдерийн тогтвортой байлгахаа амласан, дахин
хуваарилахгүй гэсэн цорын ганц claim. Холбоос нь user_sso_identities
хүснэгтэд суудаг.
Анх удаа ирсэн хүнийг гурван шатаар шийднэ:
- Холбоос байвал — тэр бүртгэл.
- Провайдерийн баталгаажуулсан и-мэйлтэй адил бүртгэл эндээс олдвол — түүнийг өвлүүлж, холбоосыг бичнэ. Энэ бол ажиллаж байгаа суулгацыг холбоосонд оруулах зам. И-мэйл нь баталгаажсан байх ёстой: эс бөгөөс профайл дээрээ хаяг бичээд хэн ч аль ч бүртгэлийг нэхэж болно.
SSO_CLIENT_TENANTтохируулсан бол — тэр байгууллагад шинэ бүртгэл үүсгэнэ. Тохируулаагүй бол баталгаажсан ч танихгүй хүнийг татгалзана: ихэнх суулгац дээр гишүүнчлэл бол зориудын үйлдэл.
Ингэж үүссэн бүртгэлд нууц үгээр нэвтрэх зам байхгүй. password_hash баганад
энэ процесс өөрөө хормын дараа мэдэхээ болих санамсаргүй утга суудаг —
subject-ээс гаргаж авсан утга байсан бол дахин тооцоолж болох тул тэр нь
холбоосон бүртгэлийн ажиллах нууц үг болох байсан.
Google-ээр нэвтрэх
Энэ бол дээрхээс өөр зүйл. Холбоос (SSO_CLIENT_ISSUER) нь эндэх нэвтрэлтийг
хаадаг; Google бол платформын өөрийнх нь нэвтрэх дэлгэц дээр eID-ийн хажууд
нэмэгдэх бас нэг товч бөгөөд юуг ч хаахгүй. Доор нь протокол нь ижил —
Google бол ердийн OpenID Connect провайдер — тул discovery, PKCE, id_token
шалгалт бүгд нэг код (ssoclient).
GOOGLE_LOGIN_CLIENT_ID=…apps.googleusercontent.com
GOOGLE_LOGIN_CLIENT_SECRET=…
Google дээр ${SSO_ISSUER}/api/v1/auth/google/callback-ийг redirect URI-аар
бүртгүүлнэ.
| Хувьсагч | Утга |
|---|---|
GOOGLE_LOGIN_REDIRECT_URI |
Өгөгдмөл ${SSO_ISSUER}/api/v1/auth/google/callback. Хөгжүүлэлтэд гараар. |
GOOGLE_LOGIN_TENANT |
Google баталгаажуулсан ч энд бүртгэлгүй хүнийг үүсгэх байгууллага. Хоосон бол хэнийг ч үүсгэхгүй. |
GOOGLE_LOGIN_ALLOWED_DOMAINS |
Зөвшөөрөгдөх и-мэйл домэйнууд, таслалаар (gerege.mn,dgov.mn). |
Яагаад GOOGLE_OAUTH_CLIENT_ID-г дахин ашиглаагүй вэ
Drive болон Meet холбогчид тэр хосыг аль хэдийн хэрэглэдэг. Нэг Google төсөл хоёуланг нь олгодог бөгөөд утга нь ижил байж болно — гэхдээ энэ нь операторын зориудын үйлдэл байх ёстой: баримтын холбогч тохируулсан нь чимээгүйхэн шинэ нэвтрэх хаалга нээж болохгүй.
Хэн орж чадах вэ
Гурван шүүлтүүр дараалан ажиллана:
- Баталгаажаагүй и-мэйлийг татгалзана. Хаяг бол эндэх бүртгэлтэй тааруулах
түлхүүр тул
email_verifiedхудал бол профайл дээрээ хаяг бичсэн хэн ч өөрийнх биш бүртгэлийг нэхэж болно. - Домэйны жагсаалт (тохируулсан бол).
- Бүртгэл олдох эсэх.
GOOGLE_LOGIN_TENANTхоосон бол Google-ийн баталгаажуулсан хаягтай аль хэдийн байгаа бүртгэл рүү л орно. Тохируулбал Google бүртгэлтэй хэн ч энд бүртгэл авч чадна — тиймээс домэйны жагсаалттай хамт тохируулна.
Бүртгэл нь (issuer, subject)-ээр холбогдоно, яг холбоосын нэгэн адил
(user_sso_identities, issuer нь https://accounts.google.com).
Гарах
Google session-ыг таслахгүй. Эндээс гарсан хүнийг Google-ээс нь гаргах нь энэ
платформын хийх ажил биш — тиймээс id_token cookie ч хадгалахгүй.
Провайдер тал: RP-initiated logout
end_session_endpoint-ийг discovery баримт бичигдсэн цагаасаа зарладаг байсан
ч тэр эндпойнт байхгүй байв. Одоо /oauth2/logout дээр байна.
- Хүсэлтийн cookie-н нэрлэсэн session-ийг хаана.
post_logout_redirect_uri-г тухайн клиентийн бүртгэлтэй жагсаалттай яг тулгана. Таарахгүй бол чиглүүлэхгүй — logout URL гэдэг клиент чөлөөтэй тарааддаг хаяг тул шалгалтгүй дагавал провайдер нээлттэй чиглүүлэгч болно.- Клиентийг
client_id-аар, эсвэлid_token_hint-аас олно. Hint-ийг зөвхөн энэ провайдерийн нийтэлсэн түлхүүрээр баталгаажсан үед л итгэнэ; баталгаажаагүйг татгалзалгүй үл тоомсорлоно — тэр үед хүн аль хэдийн гарсан байна. - Клиентийн токенуудыг хүчингүй болгохгүй: тэдэнд өөрийн эндпойнт (RFC 7009), өөрийн богино хугацаа бий. Таб хаах бүрт backend интеграцийн refresh token унтардаг байх нь logout-ийн ажил биш.
post_logout_redirect_uris нь oauth2_clients дээрх шинэ багана (migration
00041). redirect_uris-ийг дахин ашиглаагүй нь санаатай: нэвтрэх callback бол
код хүлээж авдаг машин уншдаг зам, гарсны дараах хаяг бол хүн харах хуудас.
Session cookie нь SameSite=Lax
Энэ өөрчлөлтгүйгээр SSO нь single sign-on болохгүй. Клиент суулгац хүнийг
провайдерийн /oauth2/auth руу илгээх нь өөр сайтаас ирсэн top-level
navigation бөгөөд SameSite=Strict cookie тийм хүсэлт дээр илгээгддэггүй.
Тэгэхээр authorization endpoint нь минутын өмнө нэвтэрсэн хүнийг "нэвтрээгүй"
гэж үзээд нэвтрэх дэлгэц үзүүлнэ.
CSRF-ийн хувьд алдагдал байхгүй: cookie хэзээ ч тэр хамгаалалт байгаагүй.
Төлөв өөрчлөх бүх хүсэлт security.CSRFMiddleware-ээр орох ба тэр нь манай
хуудас үүсгэсэн гэдгийн эерэг нотолгоо (зөвшөөрөгдсөн Origin, эсвэл
Sec-Fetch-Site: same-origin|none) шаарддаг. Cross-site POST нь cookie-ийн
бодлогоос үл хамааран тэнд татгалзана.
Хөгжүүлэлтэд хоёр суулгацыг холбох
# Провайдер: :8080 (API) / :3000 (вэб) — ердийн тохиргоо.
SSO_ISSUER=http://localhost:8080
OAUTH_REDIRECT_HOSTS=localhost
# Клиент: :8090 (API) / :3010 (вэб)
SSO_CLIENT_ISSUER=http://localhost:8080
SSO_CLIENT_ID=<провайдер дээр үүсгэсэн client_id>
SSO_CLIENT_SECRET=<байвал>
SSO_CLIENT_REDIRECT_URI=http://localhost:8090/api/v1/auth/sso/callback
SSO_CLIENT_POST_LOGOUT_REDIRECT_URI=http://localhost:3010/
SSO_CLIENT_TENANT=demo
Провайдер дээрх клиентийн redirect_uris-д http://localhost:8090/api/v1/auth/sso/callback,
post_logout_redirect_uris-д http://localhost:3010/ гэж бүртгэнэ. Loopback
хаягийг redirect шалгалт үргэлж зөвшөөрдөг.