add keycloak

This commit is contained in:
Mohamadzadeh 2026-06-11 19:41:48 +03:30
parent 3c1574a393
commit 72a7cc7a60
5 changed files with 1547 additions and 218 deletions

1612
dist/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -19,5 +19,8 @@
"devDependencies": {
"@vitejs/plugin-react": "4.3.4",
"vite": "5.4.19"
},
"dependencies": {
"keycloak-js": "^26.2.4"
}
}

139
src/core/keycloak.jsx Normal file
View File

@ -0,0 +1,139 @@
import Keycloak from "keycloak-js";
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from "react";
const KEYCLOAK_URL = "https://auth.ibagher.ir";
const KEYCLOAK_REALM = "bi";
let keycloakInstance = null;
let initPromise = null;
const KeycloakContext = createContext(null);
const createKeycloak = (clientId) => {
if (!keycloakInstance) {
keycloakInstance = new Keycloak({
url: KEYCLOAK_URL,
realm: KEYCLOAK_REALM,
clientId,
});
}
return keycloakInstance;
};
export const initKeycloak = ({ clientId, initOptions = {} }) => {
const keycloak = createKeycloak(clientId);
if (!initPromise) {
initPromise = keycloak.init({
onLoad: "login-required",
checkLoginIframe: false,
flow: "implicit",
...initOptions,
});
}
return initPromise;
};
export const KeycloakProvider = ({
children,
clientId,
initOptions,
loading = null,
}) => {
const [initialized, setInitialized] = useState(false);
const [authenticated, setAuthenticated] = useState(false);
const [token, setToken] = useState(null);
const mountedRef = useRef(false);
const syncState = useCallback(() => {
if (!keycloakInstance) return;
setAuthenticated(Boolean(keycloakInstance.authenticated));
setToken(keycloakInstance.token ?? null);
}, []);
useEffect(() => {
mountedRef.current = true;
initKeycloak({ clientId, initOptions })
.then((auth) => {
if (!mountedRef.current) return;
setAuthenticated(Boolean(auth));
setToken(keycloakInstance?.token ?? null);
setInitialized(true);
})
.catch(() => {
if (!mountedRef.current) return;
setAuthenticated(false);
setToken(null);
setInitialized(true);
});
return () => {
mountedRef.current = false;
};
}, [clientId, initOptions]);
const login = useCallback(() => {
return keycloakInstance?.login();
}, []);
const logout = useCallback((options) => {
return keycloakInstance?.logout(options);
}, []);
const updateToken = useCallback(
async (minValidity = 30) => {
if (!keycloakInstance) return false;
const refreshed = await keycloakInstance.updateToken(minValidity);
syncState();
return refreshed;
},
[syncState],
);
const value = useMemo(
() => ({
initialized,
authenticated,
token,
login,
logout,
updateToken,
}),
[initialized, authenticated, token, login, logout, updateToken],
);
if (!initialized) return loading;
return (
<KeycloakContext.Provider value={value}>
{children}
</KeycloakContext.Provider>
);
};
export const useKeycloak = () => {
const context = useContext(KeycloakContext);
if (!context) {
throw new Error("useKeycloak must be used inside KeycloakProvider");
}
return context;
};

View File

@ -3,3 +3,9 @@ export { toFaNumber, toFaDigits, toEnDigits } from "./utils/numbers.js";
export { LightPagination } from "./components/pagination/LightPagination.jsx";
export { Pagination } from "./components/pagination/Pagination.jsx";
export { SimplePagination } from "./components/pagination/SimplePagination.jsx";
export {
KeycloakProvider,
useKeycloak,
initKeycloak,
} from "./core/keycloak.jsx";

View File

@ -580,6 +580,11 @@ json5@^2.2.3:
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
keycloak-js@^26.2.4:
version "26.2.4"
resolved "https://registry.yarnpkg.com/keycloak-js/-/keycloak-js-26.2.4.tgz#b96ff33ed08ff6fd8d1e09d9e5055c7b3f2fa918"
integrity sha512-PnXpR3ubETGOt0B/Qt2lxmPbkZr5bc3vlQsOqDoTPPQsZRp7JjhTKxlJ187uWh8qJhvBab6Gsjb06a8ayOPfuw==
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"