SSO cho ứng dụng nội bộ: ánh xạ thuộc tính (claims) SAML/OIDC thành vai trò và nhóm
Làm SSO cho ứng dụng nội bộ an toàn hơn: ánh xạ thuộc tính SAML hoặc OIDC thành vai trò và nhóm, liên kết tài khoản và đặt mặc định khi thiếu dữ liệu.

Tại sao ánh xạ claims quan trọng với ứng dụng nội bộ
Single sign-on nghe có vẻ đơn giản: bấm "Sign in with Okta" hoặc "Sign in with Azure AD" và bạn vào được. Phần khó là chuyện xảy ra tiếp theo. Nếu không có ánh xạ claims rõ ràng, người ta có thể có quá nhiều quyền (nhân viên hỗ trợ thấy được lương) hoặc quá ít quyền (nhân viên mới không mở được công cụ họ cần ngay ngày đầu).
Ứng dụng nội bộ phức tạp hơn ứng dụng công khai vì chúng được dùng chung giữa nhiều đội và thay đổi liên tục. Một công cụ có thể được Support, Finance và Sales dùng đồng thời. Sơ đồ tổ chức thay đổi, nhà thầu đến rồi đi, đội được đổi tên hoặc tách ra. Nếu quy tắc truy cập chỉ sống trong đầu mọi người, SSO sẽ sao chép đúng mớ hỗn độn đó vào ứng dụng của bạn.
Ánh xạ claims là cách bạn biến dữ liệu định danh từ IdP (như groups, department, hay job title) thành quyền mà ứng dụng hiểu. Thường điều đó nghĩa là quyết định:
- Những vai trò nào tồn tại trong ứng dụng (admin, manager, viewer, v.v.)
- Người dùng thuộc đội/không gian làm việc nào
- Mỗi vai trò được làm gì, và mỗi đội thấy được gì
- Ai được cấp quyền tự động và ai cần phê duyệt
Có hai rủi ro gây hầu hết vấn đề:
- Ánh xạ sai. Tên nhóm khớp với vai trò sai, hoặc một nhóm chung "All Employees" vô tình cấp quyền admin.
- Claims bị thiếu. IdP không gửi groups cho một số người, một thuộc tính trống, hoặc token quá lớn bị cắt bớt.
Ứng dụng của bạn cần các mặc định an toàn để dữ liệu thiếu hay bất ngờ không bao giờ biến thành truy cập vô tình.
SAML và OIDC dưới góc nhìn đơn giản
Khi bạn đăng nhập bằng SSO, IdP gửi cho ứng dụng một gói thông tin nhỏ về bạn. Mỗi thông tin là một claim, cơ bản là một trường gắn nhãn như "email = [email protected]" hoặc "department = Finance".
SAML và OIDC đều có thể mang các thông tin tương tự, nhưng đóng gói khác nhau.
SAML phổ biến trong các môi trường doanh nghiệp cũ. Nó thường gửi một tài liệu XML (assertion) với các attributes. Những attributes đó là claims mà ứng dụng đọc.
OIDC mới hơn và xây dựng trên OAuth 2.0. Nó thường gửi một JSON token được ký (ID token) kèm user info tùy chọn, trong đó các trường bên trong token là claims.
Với ứng dụng nội bộ, bạn thường quan tâm một tập claims nhỏ:
- Địa chỉ email
- Một ID người dùng ổn định từ IdP (subject)
- Tên đầy đủ (hoặc tên và họ)
- Membership nhóm (teams, security groups)
- Phòng ban hoặc chức danh
Một phân biệt quan trọng tránh nhiều nhầm lẫn:
Xác thực (Authentication) trả lời "đây là ai?". Các claims như ID ổn định và email giúp bạn liên kết lần đăng nhập SSO với đúng tài khoản.
Phân quyền (Authorization) trả lời "họ có thể làm gì?". Các claims như groups hoặc department giúp ánh xạ người dùng vào vai trò và nhóm trong ứng dụng.
Hai người có thể xác thực thành công, nhưng chỉ người có claim "Finance" mới được vào màn hình thanh toán.
Vai trò và nhóm: quyết định bạn sẽ ánh xạ tới gì
Trước khi ánh xạ attribute SAML hoặc chuyển claims OIDC thành quyền, hãy rõ hai thứ ứng dụng bạn cần biết:
- Vai trò (roles) định nghĩa ai có thể làm gì (permissions).
- Nhóm (teams) định nghĩa nơi họ thuộc về (phạm vi).
Vai trò trả lời các câu như: người này có thể xem, sửa, phê duyệt, xuất, quản lý người dùng hay thay đổi cài đặt không?
Nhóm trả lời các câu như: người này làm ở phòng ban, vùng, hàng đợi hay mã chi phí nào, và họ nên thấy bản ghi nào?
Giữ vai trò nhỏ và ổn định. Hầu hết ứng dụng nội bộ chỉ cần vài vai trò hiếm khi thay đổi, ngay cả khi người di chuyển. Nhóm nên phản ánh thực tế hàng ngày: Support Tier 2, phạm vi EMEA, một chủ hàng đợi tạm thời.
Nguyên tắc ít quyền nhất (least privilege) là mặc định an toàn. Nhiều ứng dụng nội bộ hoạt động tốt với ba vai trò:
- Người xem: chỉ đọc dữ liệu và tìm kiếm
- Người chỉnh sửa: tạo và cập nhật bản ghi
- Quản trị viên: quản lý cài đặt, người dùng và quy tắc truy cập
Viết rõ bằng ngôn ngữ đơn giản những gì mỗi vai trò được phép. Điều này ngăn "quyền admin bất ngờ" khi tên nhóm thay đổi và giúp đánh giá dễ dàng về sau.
Truy cập theo nhóm: suy nghĩ về nhóm trong IdP
Truy cập theo nhóm nghĩa là ứng dụng không quyết định từng người một. Thay vào đó, IdP duy trì membership nhóm, và ứng dụng của bạn ánh xạ các nhóm đó thành vai trò và nhóm trong app.
Bắt đầu bằng việc quyết định một nhóm cấp gì. Trong nhiều công cụ, một nhóm ánh xạ tới một vai trò (như "Support Agent") và tùy chọn một nhóm ứng dụng (như "Tier 2"). Điều quan trọng là ánh xạ phải nhàm và dễ đoán: cùng một nhóm luôn có nghĩa cùng một quyền.
Khi người dùng thuộc nhiều nhóm
Mọi người thường nằm trong hơn một nhóm IdP. Bạn cần một quy tắc để giải quyết điều đó, và quy tắc đó phải ổn định.
Các cách phổ biến:
- Quy tắc cộng dồn: kết hợp quyền từ tất cả nhóm khớp (phù hợp khi quyền được giới hạn chặt)
- Quy tắc ưu tiên: lấy nhóm ưu tiên nhất và bỏ qua phần còn lại (hữu ích khi vai trò xung đột)
- Kết hợp: cộng dồn cho nhóm, ưu tiên cho vai trò
Dù chọn cách nào, hãy ghi lại. Thay đổi sau này có thể khiến người dùng đột ngột được hoặc mất quyền.
Dùng quy ước đặt tên có thể mở rộng
Tên nhóm rõ ràng giảm lỗi và giúp kiểm toán dễ hơn. Một mẫu thực tế là:
- -
Ví dụ: support-tool-prod-agent hoặc finance-tool-staging-viewer. Điều này giúp tránh tái sử dụng các tên mơ hồ như "Admins" cho nhiều app.
Nếu người dùng không thuộc nhóm liên quan nào, mặc định không được truy cập (hoặc trạng thái guest hạn chế) và hiển thị thông báo giải thích cách yêu cầu quyền.
Liên kết tài khoản: khớp người SSO với tài khoản trong app
SSO chứng minh người đó là ai, nhưng ứng dụng vẫn phải quyết định gắn nhận dạng đó vào tài khoản nào. Không có liên kết tài khoản, cùng một người có thể có nhiều tài khoản theo thời gian vì các định danh thay đổi: email mới, cập nhật tên, chuyển giữa công ty, đổi IdP.
Chọn một khóa ổn định, duy nhất làm chìa khóa chính.
- Với OIDC, thường là claim
sub(subject). - Với SAML, thường là một NameID bền vững hoặc một thuộc tính user ID bất biến.
Lưu giá trị đó làm "IdP user ID" cùng với issuer/entity ID của IdP, để cùng một sub từ IdP khác không va chạm.
Email hữu ích nhưng chỉ là khoá tiện lợi, không phải nguồn chân lý. Người ta đổi email, di chuyển domain, hay hợp nhất công ty. Aliases và hộp thư chia sẻ cũng có thể gây trùng. Nếu khớp bằng email, chỉ làm khi tín hiệu IdP được xác minh, và cân nhắc bước xác nhận một lần.
Lần đăng nhập đầu tiên, nhiều công cụ nội bộ chọn một trong các mẫu onboard:
- Tự động tạo: tạo tài khoản ngay và gán quyền tối thiểu.
- Chỉ mời: chỉ cho phép đăng nhập cho người được tạo trước (hoặc phê duyệt trước) trong app.
- Luồng phê duyệt: tạo tài khoản nhưng khoá truy cập cho đến khi quản lý hoặc admin phê duyệt vai trò/nhóm.
Mặc định an toàn: tự động tạo nhưng không có quyền, sau đó cấp quyền dựa trên nhóm hoặc bước phê duyệt.
Các bước: ánh xạ claims tới vai trò và nhóm
Ánh xạ claims tốt khiến SSO gần như vô hình: người dùng đăng nhập và đến đúng nơi với quyền đúng.
Bắt đầu bằng việc viết mô hình truy cập bằng ngôn ngữ đơn giản. Liệt kê từng vai trò (Viewer, Agent, Manager, Admin) và từng nhóm (Support, Finance, IT), ai nên có và vì sao.
Rồi xác nhận IdP thực sự có thể gửi gì. Với SAML hoặc OIDC, bạn thường muốn ID người dùng ổn định (subject hoặc NameID), email, và một hoặc nhiều thuộc tính nhóm. Ghi lại giá trị nhóm chính xác như xuất hiện, kể cả chữ hoa chữ thường và tiền tố. "Support" và "support" không giống nhau.
Một luồng thực tế:
- Định nghĩa vai trò và nhóm, và chỉ định một người chịu trách nhiệm cho mỗi cái (người có thể phê duyệt thay đổi).
- Liệt kê claims khả dụng và tên nhóm chính xác từ IdP, kể cả các trường hợp méo mó (nhà thầu, hộp thư chia sẻ).
- Viết quy tắc ánh xạ: group-to-role, group-to-team, và thứ tự override khi nhiều nhóm khớp.
- Thử với 3–5 loại người dùng thực tế (nhân viên mới, quản lý, nhà thầu, admin) dùng tài khoản IdP thật.
- Với mỗi user test, viết trước kết quả vai trò/nhóm mong đợi, rồi đăng nhập và so sánh.
Giữ một ví dụ nhỏ để làm quy tắc cụ thể. Nếu người dùng ở okta-support, họ thành đội Support và vai trò Agent. Nếu họ cũng ở okta-support-managers, vai trò Manager ghi đè Agent.
Cuối cùng, thêm cách gỡ lỗi đơn giản. Ghi log claims thô nhận được (an toàn), các quy tắc đã khớp và kết quả vai trò/nhóm cuối cùng. Khi ai đó nói "Tôi đã đăng nhập nhưng không thấy công cụ", điều này biến trò chơi đoán thành kiểm tra nhanh.
Mặc định an toàn khi claims bị thiếu
Claims thiếu là bình thường. IdP có thể không gửi groups cho service account, connector có thể bỏ một trường, hoặc người dùng đang giữa quá trình di cư. Xử lý "không có dữ liệu" như "không tin cậy".
Mặc định an toàn nhất là deny-by-default: không vai trò, không nhóm, không truy cập. Nếu phải cho phép vào để yêu cầu truy cập, giữ quyền chỉ đọc và rõ ràng hạn chế.
Chọn một hành vi và ghi lại:
- Chặn đăng nhập với thông báo rõ ràng: "Tài khoản của bạn chưa được gán quyền. Liên hệ support."
- Cho phép truy cập hạn chế với cảnh báo và tắt các hành động nhạy cảm.
- Tạo bản ghi người dùng nhưng không gán vai trò/nhóm cho tới khi được phê duyệt.
Không bao giờ mặc định thành admin, kể cả tạm thời.
Lên kế hoạch cho dữ liệu từng phần. Nếu bạn nhận email nhưng không có groups, vẫn có thể tạo tài khoản và chuyển sang luồng phê duyệt. Nếu nhận groups nhưng không có định danh ổn định, tránh tự động liên kết với tài khoản hiện có vì có thể gán nhầm người.
Có một đường leo thang khi thất bại:
- Một chủ thể có tên (IT hoặc admin app) có thể phê duyệt truy cập
- Luồng gán vai trò thủ công với ghi chú audit
- Cách kiểm tra lại claims ở lần đăng nhập tiếp theo
- Thời gian chờ cho tài khoản "pending access"
Xử lý thay đổi, loại bỏ và offboarding
Mọi người chuyển đội, đổi quản lý và rời công ty. Cấu hình SSO nên coi đó là điều bình thường.
Khi ai đó đổi đội, cập nhật quyền ở lần đăng nhập tiếp theo: đánh giá lại group claims và áp dụng ánh xạ hiện hành. Tránh quyền "dính" mãi vì đã từng được cấp.
Người rời công ty khác. Chờ lần đăng nhập tiếp theo không đủ. Bạn muốn quyền của họ chấm dứt nhanh, ngay cả khi vẫn còn session còn hoạt. Thường điều đó nghĩa là vô hiệu hóa tài khoản ở IdP, và ứng dụng nên coi danh tính bị vô hiệu hoặc mất là bị chặn ngay.
Deprovision nên rõ ràng: vô hiệu hóa người dùng, xoá membership nhóm và giữ dữ liệu audit. Bạn thường cần bảo toàn hồ sơ như phê duyệt, bình luận và lịch sử cho tuân thủ, đồng thời chặn các hành động mới.
Nhà thầu và quyền tạm thời cần chú ý hơn. Đặt họ vào nhóm có thời hạn trên IdP, hoặc gắn ngày kiểm tra cho vai trò để quyền không kéo dài sau khi dự án kết thúc.
Một chính sách offboarding thực tế:
- Kiểm tra lại claims ở mỗi lần đăng nhập và làm mới membership đội từ IdP
- Khi người dùng bị xoá khỏi nhóm cần thiết, giảm quyền ngay lập tức (lần đăng nhập tiếp theo hoặc lần đồng bộ tiếp theo)
- Vô hiệu hóa tài khoản nhưng giữ lại nhật ký audit và lịch sử sở hữu
- Yêu cầu ngày kết thúc cho quyền của nhà thầu và rà soát trước khi gia hạn
- Chạy kiểm tra truy cập định kỳ cho vai trò nhạy cảm như finance hoặc admin
Sai lầm thường gặp và bẫy cần tránh
Hầu hết sự cố SSO không phải do SAML hay OIDC "khó". Chúng xảy ra vì ứng dụng giả định không an toàn về con người, nhóm và định danh.
Một sai lầm phổ biến là trộn ánh xạ vai trò với ánh xạ nhóm. Vai trò là "họ có thể làm gì?" Nhóm là "họ thuộc về đâu?" Nếu bạn ánh xạ trực tiếp một nhóm thành vai trò quyền lực như Admin, bạn dễ cấp quyền rộng cho bất kỳ ai trong nhóm đó.
Bẫy khác là dựa vào email làm định danh duy nhất cho liên kết tài khoản. Email thay đổi, alias có thể tạo trùng. Ưu tiên ID IdP ổn định (như sub/NameID) làm khoá chính và coi email là trường hiển thị/thông báo.
Một số vấn đề thường gặp khác:
- Mở mặc định khi groups bị thiếu (hãy mặc định không truy cập hoặc truy cập thấp, không phải truy cập đầy đủ)
- Tên nhóm mơ hồ được tái sử dụng giữa dev, staging và production
- Đối xử membership nhóm như danh sách quyền mà không rà soát ý nghĩa từng nhóm
- Không xử lý người dùng đa nhóm cần quyền ở hơn một khu vực mà không biến họ thành admin
- Quên partners và nhà thầu nên được tách khỏi nhóm riêng cho nhân viên
Thử các trường hợp biên trước khi ra mắt. Một nhà phân tích tài chính trong phản ứng sự cố có thể cần hai nhóm và một vai trò nâng cao. Nếu quy tắc của bạn chỉ cho phép một nhóm, họ sẽ mất truy cập hoặc bị cấp quá nhiều quyền.
Danh sách kiểm tra nhanh trước khi bật
Trước khi bật SSO cho mọi người, chạy thử với một vài tài khoản test từ mỗi đội. Hầu hết vấn đề truy cập hiện ngay khi bạn thử nhân viên mới, thay đổi vai trò và offboarding.
Bắt đầu với liên kết tài khoản. Chọn một định danh duy nhất không thay đổi theo thời gian, và giữ nguyên. Với OIDC thường là sub. Với SAML thường là NameID hoặc một thuộc tính bất biến.
Tiếp theo, quyết định xử lý khi claims bị thiếu. Mặc định an toàn là không cấp quyền nâng cao (và trong nhiều app, không cho truy cập) khi group hoặc role claim vắng mặt hoặc rỗng. Đảm bảo bạn có ít nhất một vai trò quyền thấp để cho người dùng vào mà không lộ hành động nhạy cảm, nếu phù hợp.
Một checklist đơn giản trước khi ra mắt:
- Xác nhận định danh liên kết ổn định và duy nhất (và bạn có thể thấy nó trong log)
- Xác minh nhóm thiếu không cấp quyền vượt quá vai trò thấp
- Yêu cầu quyền admin phải tương ứng nhóm admin rõ ràng, cộng thêm bước phê duyệt thứ hai (dù thủ công)
- Thử việc xoá: khi người dùng rời nhóm, quyền giảm ở lần đăng nhập tiếp theo (hoặc lần đồng bộ)
- Viết quy tắc ánh xạ sao cho đồng đội có thể hiểu chỉ trong một trang
Ví dụ: công cụ nội bộ cho support và finance với nhóm SSO
Hình dung một công cụ vận hành được Support, Finance và vài quản lý dùng hàng ngày. Bạn muốn họ đăng nhập và nhận đúng màn hình, hành động mà không cần admin chỉnh tay.
Tạo vài nhóm IdP và ánh xạ chúng vào vai trò và nhóm trong app:
ops-support-> Vai trò: Support Agent, Nhóm: Supportops-finance-> Vai trò: Finance Analyst, Nhóm: Financeops-managers-> Vai trò: Manager, Nhóm: Management
Diễn biến như sau.
| User | IdP identifier used for linking | IdP groups claim | In-app result | Notes |
|---|---|---|---|---|
| Maya (Support) | sub=00u8...k3 | ops-support | Support Agent, nhóm Support | Có thể xem ticket, trả lời và gắn thẻ. Không thấy trang thanh toán. |
| Omar (Manager) | sub=00u2...p9 | ops-support, ops-managers | Manager, nhóm Management | Quy tắc ánh xạ chọn vai trò cao hơn, trong khi Finance vẫn tách riêng. |
| Lina (Finance) | sub=00u5...w1 | Missing (group claim not sent) | Mặc định: Không truy cập (hoặc Khách chỉ đọc) | Mặc định an toàn ngăn truy cập quá tay. Lina thấy: "Access not assigned. Contact admin." |
Bây giờ trường hợp đổi email: Omar đổi từ [email protected] sang [email protected]. Vì app liên kết bằng IdP user ID ổn định (như sub cho OIDC, hoặc NameID bền cho SAML) thay vì email, anh ấy không có tài khoản trùng lặp. Lịch sử và audit của anh ấy được giữ nguyên.
Để kiểm tra truy cập không phải đoán, giữ một "effective access" view hiện danh tính IdP đã liên kết của user, các nhóm nhận được, vai trò và nhóm kết quả. Khi có gì đó sai, bạn nhanh chóng biết đó là vấn đề IdP, quy tắc ánh xạ hay claim bị thiếu.
Bước tiếp theo: giữ quyền truy cập dự đoán khi tổ chức thay đổi
Phần khó nhất không phải là ra mắt ban đầu. Là duy trì quyền truy cập ổn sau khi tái cơ cấu, ra đội mới và ngoại lệ tạm thời.
Giữ một tài liệu ánh xạ trên một trang trả lời:
- Nhóm IdP nào ánh xạ tới vai trò và nhóm trong app
- Mặc định khi claim bị thiếu là gì (và ai phê duyệt thay đổi)
- Ai chịu trách nhiệm cho vai trò rủi ro cao (finance admin, user admin, export data)
- Cách xử lý nhà thầu và service account
- Nơi lưu nguồn chân lý (IdP hay app)
Chạy một pilot nhỏ với một bộ phận có ranh giới rõ, sửa các trường hợp biên, rồi mở rộng mà không sáng tạo quy tắc mới. Đặt lịch rà soát định kỳ cho các quyền có thể gây thiệt hại thực sự: hàng tháng cho admin và vai trò rủi ro cao, hàng quý cho vai trò bình thường.
Nếu bạn tự xây ứng dụng nội bộ, sẽ thuận tiện khi vai trò, nhóm và logic nghiệp vụ ở gần nhau để thay đổi dễ kiểm thử. AppMaster (appmaster.io) là một lựa chọn cho các đội muốn mô hình hóa vai trò và workflow trực quan và sinh lại mã backend, web và mobile thực tế khi yêu cầu thay đổi, thay vì chất đống các bản vá quyền một-off.
Câu hỏi thường gặp
Ánh xạ claims là bước bạn dịch những gì nhà cung cấp nhận dạng (IdP) gửi lên (như nhóm, phòng ban, hay chức danh) thành vai trò và nhóm mà ứng dụng của bạn dùng để kiểm soát truy cập. Nếu không có nó, người dùng có thể đăng nhập thành công nhưng lại nhận quyền không đúng.
Mặc định tốt là từ chối theo mặc định (deny-by-default): tạo hoặc nhận diện người dùng nhưng không gán vai trò hay nhóm nào cho đến khi có ánh xạ rõ ràng. Nếu cần cho phép người dùng yêu cầu truy cập, giữ phạm vi rất hạn chế và không bao giờ coi thiếu dữ liệu là quyền.
Dùng một khoá định danh bất biến, ổn định từ IdP làm đối chiếu chính, ví dụ claim sub của OIDC hoặc một NameID/thuộc tính bất biến trong SAML. Lưu giá trị đó kèm theo issuer/entity ID của IdP để cùng một sub từ IdP khác không bị trùng lẫn.
Email nên là thuộc tính tiện lợi, không phải nguồn dữ liệu chính, vì email có thể thay đổi do đổi tên, di chuyển domain hoặc sáp nhập. Nếu dùng email để khớp, chỉ làm khi đã xác minh mạnh mẽ từ IdP và cân nhắc bước xác nhận một lần để tránh liên kết sai người.
Vai trò định nghĩa người đó có thể làm gì — ví dụ chỉnh sửa, phê duyệt, xuất dữ liệu, quản lý người dùng. Nhóm định nghĩa nơi họ thuộc về và phạm vi dữ liệu họ thấy — ví dụ phòng ban, vùng, hàng đợi hay mã chi phí.
Một điểm khởi đầu đơn giản là ba vai trò: Người xem (Viewer), Người chỉnh sửa (Editor) và Quản trị viên (Admin), với định nghĩa rõ ràng cho từng vai trò. Giữ số vai trò nhỏ và ổn định giúp giảm lỗi khi cấu trúc tổ chức thay đổi.
Chọn một quy tắc phân giải nhất quán và ghi lại nó để quyền không thay đổi thất thường. Nhiều đội dùng cách kết hợp: cộng dồn membership cho nhóm (additive) còn vai trò thì ưu tiên theo thứ tự (priority) để tránh xung đột quyền.
Quy ước tên nhóm nên bao gồm tên app, môi trường và vai trò để rõ ràng quyền truy cập. Điều này ngăn các nhóm mơ hồ như “Admins” được tái sử dụng giữa các ứng dụng hoặc vô tình áp lên production.
Ghi đủ thông tin để biết những claims nào tới, quy tắc nào khớp và vai trò/nhóm cuối cùng được gán, nhưng không lộ nội dung token nhạy cảm. Điều này biến “tôi không thấy công cụ” thành việc so sánh nhanh claims với quy tắc.
Đánh giá lại claims ở mỗi lần đăng nhập hoặc đồng bộ định kỳ để thay đổi quyền theo membership hiện tại thay vì để quyền “dính” mãi. Khi offboarding, không nên chờ người đó đăng nhập lần tới; vô hiệu hoá ở IdP phải ngay lập tức chặn truy cập và ứng dụng vẫn giữ lịch sử audit khi chặn hành động mới.


