Giới thiệu về Keycloak - Giải pháp cho quản lý đăng nhập, xác thực và phân quyền
Theo dõi thêm mình tại đây
Lý thuyết
Giới thiệu tổng quan
Keycloak là một giải pháp quản lý danh tính tập trung, do Red Hat phát triển, hỗ trợ
- Single Sign-On (SSO): Người dùng chỉ cần đăng nhập một lần để truy cập nhiều ứng dụng.
- OAuth2, OIDC, SAML 2.0: Đầy đủ các tiêu chuẩn xác thực hiện đại.
- User Management: Tạo user, nhóm, vai trò, đặt password policy, khóa tài khoản, TOTP/2FA…
- Identity Brokering & Social Login: Cho phép đăng nhập bằng Google, Facebook, GitHub…
- Client & Resource Permissions (RBAC/ABAC): Phân quyền theo role hoặc theo resource.
- Admin Console & Account Console: Giao diện trực quan giúp quản lý dễ dàng.
Các thành phần chính của Keycloak
- Realm – Tập hợp user, client, role, policy (giống 1 tenant)
- Client – Ứng dụng kết nối với Keycloak (web, backend, mobile)
- Users – Tài khoản người dùng
- Roles/Groups – Phân quyền
- Identity Providers – Google, SAML IdP, Azure AD…
- User Federation – Kết nối LDAP/AD để đồng bộ user
Thực hành
Chạy Keycloak với Docker và kết nối với Database riêng
Chuẩn bị: Máy có cài docker
File docker-compose.yml:
services:
maria-db:
image: mariadb:12.0
container_name: mariadb
ports:
- "3307:3306"
environment:
MARIADB_ROOT_PASSWORD: secret
MARIADB_DATABASE: keycloak
MARIADB_USER: keycloak
MARIADB_PASSWORD: secret
networks:
- keycloak-network
keycloak:
image: quay.io/keycloak/keycloak:26.4.4
container_name: keycloak
ports:
- "8080:8080"
command: start-dev
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB: mariadb
KC_DB_URL: jdbc:mariadb://mariadb:3306/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: secret
KC_HTTP_ENABLED: "true"
KC_HOSTNAME_STRICT: "false"
KC_PROXY: "edge"
depends_on:
- maria-db
networks:
- keycloak-network
networks:
keycloak-network:
driver: bridge
Giải thích:
- Trong file docker-compose trên chúng ta khai báo 2 container là: mariadb và keycloak
- Trong mục enviroment của keycloak, chúng ta khai báo 3 biến là: KC_DB, KC_DB_URL, KC_DB_USERNAME, KC_DB_PASSWORD. Giúp keycloak dùng mariadb là database để lưu trữ dữ liệu
- Khai báo networks là keycloak-network để 2 container join vào và sử dụng chung mạng kết nối này
Chạy 2 container bằng docker compose
Chạy câu lệnh:
docker compose up
Mở docker desktop và xem thành quả
- Hai container mariadb và keycloak đã chạy lên với đúng port được cấu hình ở file docker-compose.yml

Kết nối với database
- Dùng các công cụ để kết nối với database với các thông tin về host, port, username và password mà chúng ta cấu hình
- Chúng ta thấy database keycloak đã tạo sẵn ra rất nhiều bảng. Keycloak sẽ dùng những bảng này để lưu trữ dữ liệu để phục vụ quản lý đăng nhập, xác thực và phân quyền

Truy cập key cloak
- Mở trình duyệt và truy cập vào localhost:8080 để truy cập keycloak
- Đăng nhập keycloak bằng user, password mặc định. User: admin, pass: admin

Tạo realm mới
- Vào Manage realm, chọn button Create Realm sẽ hiện popup để tạo Realm
- Nhập Realm name. Chọn Create, để tạo Realm mới

Tạo User mới
- Chọn User, sau đó chọn button create new user
- Nhập Username, First Name và Last Name của user
- Các tùy chọn khác mình sẽ giới thiệu ở một bài viết khác
- Click Create để tạo User mới

Tạo user mới thành công

Xem user mới tạo trong bảng USER_ENTITY trong database

Tạo client mới
- Chọn mục client trên thanh menu bên trái màn hình
- Ở trong trang màn hình client chọn button Create client
- Màn hình Tạo client hiện ra. Ta nhập các thông tin cần thiết cho client mới như ảnh dưới. Sau đó chọn Next

- Ở bước tiếp theo là Capability config, enable Client authentication. Chọn Next
- Sau đó chọn Save để lưu client mới này
- Bước tiếp theo ta sẽ cấu hình thêm cho client mới tạo. Ở màn hình client mới tạo, ta chọn Mục Credentials. Ta thấy có mục client Secret, ta sẽ lấy thông tin này để dùng cho cách bước lấy token và verify dưới đây

Lấy token của user
Khi tạo user thành công như các bước trên, chúng ta có thể lấy token của user đó. Bằng cách gửi API đến Keyloak như sau
- Phương thức: POST
- URL: http://{host}:{post}/realms/{realm_name}/protocol/openid-connect/token
- Ví dụ như CURL:
curl --location 'http://localhost:8080/realms/myrealm/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=myclient' \
--data-urlencode 'client_secret=mSe0xrOLaL8lV5aE0dyHYDcT1OYur94U' \
--data-urlencode 'username=hungnv' \
--data-urlencode 'password=123456'
Và chúng ta có kết quả như hình dưới khi gửi bằng Postman

Verity token
Khi đã lấy được token rồi. Nếu muốn verify token đó. Ta có thể dùng API sau của Keycloak để verify:
- Phương thức: POST
- URL: http://{host}:{post}/realms/{realm_name}/protocol/openid-connect/introspect
- Ví dụ CURL:
curl --location 'http://localhost:8080/realms/myrealm/protocol/openid-connect/token/introspect' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=myclient' \
--data-urlencode 'token=eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2NGFZdXM2amUxTVpOc1ZNalJJb01icjNsMWdIUFB0bXYwRXJ4Z280bnBZIn0.eyJleHAiOjE3NjU2MTkyMDQsImlhdCI6MTc2NTYxODkwNCwianRpIjoib25ydHJvOjc2ZjcwNTBlLTY5OTAtOGNlYi0zYThiLWVhMDg2NWY5ZGMyNiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9yZWFsbXMvbXlyZWFsbSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJkMjUxNjAyYy1kMDYxLTQ4NTAtYjZkYi04ZDU1YjdiNGM2MmEiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJteWNsaWVudCIsInNpZCI6IjUzN2QyMDM3LWZiY2MtNDdlMC1lZmU1LTQ4MGVjYzc4OWU5NyIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbImRlZmF1bHQtcm9sZXMtbXlyZWFsbSIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6InByb2ZpbGUgZW1haWwiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJIdW5nIE5ndXllbiIsInByZWZlcnJlZF91c2VybmFtZSI6Imh1bmdudiIsImdpdmVuX25hbWUiOiJIdW5nIiwiZmFtaWx5X25hbWUiOiJOZ3V5ZW4iLCJlbWFpbCI6Imh1bmduZ3V5ZW51ZXRAZ21haWwuY29tIn0.QCDoldb6nuLF7eMIzHLUGWyjOqvXE8wftHzXUUooSKKYAWkAg0XNZdJxkMxEe9rF2WC4CTzR4AyF3WtH-KY-clEJrrA4L6G9GcI6d1bySxLVtOkTH-F_nDlVYjAAGLi2Cq21Ahy6siu8xSjWt7mgAeglBJmlwAESPEyEcLIG4DHvhocnfZENfxjfAl7kM4DZe5CIE3EWgGo8btsGswZGkX8dzRotnzjZW5TLM4Ew9_EFjPBUeOOIyIpvGheoYw7G5KXydUB_PVetAZ7yOpJO1L2kHluokDjiS5ZWBKkYQCRCz8F8pw9pkgmXVMSlG_bLaAnuSdqso9i7yK3GNujWJQ' \
--data-urlencode 'client_secret=mSe0xrOLaL8lV5aE0dyHYDcT1OYur94U'
Nếu token hợp lệ, Keycloak sẽ phản hồi chúng ta lại thông tin như sau:
{
"exp": 1765619204,
"iat": 1765618904,
"jti": "onrtro:76f7050e-6990-8ceb-3a8b-ea0865f9dc26",
"iss": "http://localhost:8080/realms/myrealm",
"aud": "account",
"sub": "d251602c-d061-4850-b6db-8d55b7b4c62a",
"typ": "Bearer",
"azp": "myclient",
"sid": "537d2037-fbcc-47e0-efe5-480ecc789e97",
"acr": "1",
"allowed-origins": [
"/*"
],
"realm_access": {
"roles": [
"default-roles-myrealm",
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "profile email",
"email_verified": false,
"name": "Hung Nguyen",
"preferred_username": "hungnv",
"given_name": "Hung",
"family_name": "Nguyen",
"email": "hungnguyenuet@gmail.com",
"client_id": "myclient",
"username": "hungnv",
"token_type": "Bearer",
"active": true
}
Cảm ơn các bạn đã đọc bài viết. Nếu có bất kỳ thắc mắc và góp ý mong mọi người comment ở dưới cho mình nhé!
Theo dõi thêm mình tại đây
All rights reserved