Single Sign-On (SSO) là một kỹ thuật xác thực người dùng cho phép người dùng đăng nhập vào nhiều ứng dụng khác nhau mà không cần phải nhập tên đăng nhập và mật khẩu cho mỗi ứng dụng. SSO giúp người dùng dễ dàng quản lý tài khoản và giảm thiểu số lần người dùng phải nhập thông tin đăng nhập.
Keycloak là một hệ thống quản lý xác thực và quyền truy cập (Identity and Access Management - IAM) miễn phí và mã nguồn mở, cho phép bạn xây dựng các giải pháp SSO cho các ứng dụng web và mobile. Keycloak cung cấp một giao diện người dùng để quản lý người dùng, tài khoản và quyền truy cập, và có thể tích hợp với các hệ thống xác thực khác nhau như LDAP, SAML, v.v. Keycloak cũng hỗ trợ các tính năng bảo mật như bảo mật mật khẩu, xác thực hai yếu tố, v.v.
Để sử dụng SSO (Single Sign-On) Keycloak trong React, bạn có thể thực hiện các bước sau:
- Cài đặt thư viện keycloak-js:
- Trước tiên, bạn cần cài đặt thư viện keycloak-js bằng câu lệnh sau:
npm install keycloak-js
- Sau đó, bạn có thể khởi tạo một đối tượng Keycloak như sau:
import Keycloak from 'keycloak-js'; const keycloak = new Keycloak({ url: 'http://keycloak-server/auth', realm: 'myrealm', clientId: 'myclient',
});
Trong đoạn code trên, chúng ta khởi tạo Keycloak với các thông tin:
- url: Địa chỉ máy chủ Keycloak.
- realm: Tên realm đã được cấu hình trên máy chủ Keycloak.
- clientId: Tên client đã được cấu hình trên máy chủ Keycloak.
- Tiếp theo, viết một function implement tất cả các phương thức của đối tượng keycloak vừa tạo.
import { KeycloakEnum } from "../enum/KeyCloakEnum";
import keycloak from "./keycloack"; const initKeycloak = (onAuthenticatedCallback: Function, logout: Function) => { // khởi tạo đối tượng keycloak keycloak.init({ onLoad: "check-sso", enableLogging: true, pkceMethod: "S256", silentCheckSsoRedirectUri: window.location.origin + '/silent-check-sso.html' }) .then((authenticated: boolean) => { if (!authenticated) { isSSO && logout(); } return onAuthenticatedCallback(); }) .catch((e) => { return console.error; });
}; const getKeyCloack = () => keycloak; const doLogin = keycloak.login; // đăng nhập const doLogout = keycloak.logout; // đăng xuất const getToken = () => keycloak.token; // lấy token const isLoggedIn = () => keycloak.authenticated; // kiểm tra trạng thái đăng nhập const getUsername = () => keycloak.tokenParsed?.realm_access; // lấy thông tin user const hasRole = (roles: string[]) => roles.some((role: string) => keycloak.hasRealmRole(role)); // kiểm tra quyền const UserService = { initKeycloak, doLogin, doLogout, isLoggedIn, getToken, getUsername, hasRole, getKeyCloack
}; export default UserService;
- Sử dụng function vừa tạo ở trên trong lớp container của ứng dụng để check đăng nhập:
// code khởi tạo ứng dụng.... UserService.initKeycloak(renderApp, () => { action.clearAuthentication(); action.clearSearchInfo(); action.clearSitesMap();
});
- Sau khi khởi tạo xong, chúng ta tạo 2 class router để điều hướng cho ứng dụng:
- Class chỉ được truy cập khi đã được đăng nhập:
export default function AuthenticationRouter(props: { children: JSX.Element }) { const { children } = props; const auth = UserService.isLoggedIn(); //kiểm tra đã đăng nhập chưa bằng method isLoggedIn của keycloak if (auth) { return children; } else { return <Navigate to="/login" />; }
}
- Class được truy cập khi không cần đăng nhập sẽ check ngược lại với class trên:
export default function ProtectedRouter(props: { children: JSX.Element }) { const { children } = props; const location = useLocation(); const auth = UserService.isLoggedIn(); if (!auth) { return children; } else { return <Navigate to="/" state={{ from: location }} />; }
}
- Kết nối API:
- Sau khi người dùng đăng nhập thành công, bạn có thể sử dụng token truy cập của người dùng để gọi các API có yêu cầu xác thực. Để lấy token truy cập, bạn có thể sử dụng phương thức keycloak.token. Ví dụ:
axios.get('http://api-server/protected-resource', { headers: { Authorization: `Bearer ${UserService.getToken()}`, },
});
- Tài liệu tham khảo để sử dụng với các framework khác: https://keycloak-docs.github.io/deploy-docs/dev/master/securing_apps/index.html#_javascript_adapter