admin管理员组文章数量:1292556
Okay after ramming with this for several days I have to kindly ask the community.
I have a Svelte project, which integrates with Keycloak instance. All my keycloak functions are located in separate keycloakInteraction.ts
from which i reuse them.
My goal is: initialize the keycloak instance (enter login and password if previous session rotten or didn't exist) and then serve particular data based on obtained token.
The problem is that +layout.server.ts
that is serving data is executed prior to +layout.svelte that initializes keycloak, and while there is no token yet +layout.server.ts
serves empty array.
One of the workarounds is just to reload the page, so when the page is reset after user logged in, token is already in memory and data can be served.
However in my implementation the page won't automatically reset if the token has been expired and user has to relogin in the same window. I can't figure out how to workaround it with the variables. I also wonder if there are other graceful ways to login and then serve content based on user_group keycloak token property without reloading the page.
Any ideas will be much appreciated.
my +layout.svelte
:
<script>
import '../app.css';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import {
initKeycloakOnClient,
keycloakClientTokenStoreOnClient,
} from '$lib/keycloakInteraction';
export let data;
$: keycloakState = $keycloakClientTokenStoreOnClient;
$: isAuthenticated = keycloakState.authenticated;
onMount(async () => {
await initKeycloakOnClient();
hasReloaded = sessionStorage.getItem("hasReloadedAfterLogin");
if (isAuthenticated && !hasReloaded) {
console.log("User just logged in, reloading the page...");
sessionStorage.setItem("hasReloadedAfterLogin", "true");
location.reload();
}
});
</script>
{#if isAuthenticated}
<!--MENU HTML CODE IS HERE-->
{#each data.routes as route}
{/each}
<!--...and other data used provided by +layout.server.ts-->
<slot />
{:else}
<div class="h-screen flex justify-center items-center">
<p>Loading...</p>
</div>
{/if}
My +layout.server.ts
:
import type { LayoutServerLoad } from './$types';
import { selectAllClients, selectAllEngagements } from '$lib/server/database/queries';
import {
validateClientTokenOnServer,
resetKeycloakClientTokenStore
} from '$lib/keycloakInteractionResource';
import { keycloak } from '$lib/keycloakInteraction';
const routes = [
{
name: 'Link#1',
},
{
name: 'Link#2',
}
];
export const load: LayoutServerLoad = async ( request ) => {
let userGroup: string = null;
//getting clientToken from server-side cookies that were put by storeKeycloakTokenOnServer()
const clientToken = request.cookies.get('client_token');
if (clientToken) {
await validateClientTokenOnServer(clientToken);
const decodedToken = JSON.parse(atob(clientToken.split(".")[1]));
userGroup = decodedToken?.user_groups || [];
const availableData = await selectAllData(userGroup);
const availableRoutes = userGroup.includes("testGroup") ? routes.filter(route => route.name !== 'Link#2') : routes;
await resetKeycloakClientTokenStore();
return {
data: availableData,
routes: availableRoutes
}
}
}
My keycloakInteraction.ts
:
import Keycloak from 'keycloak-js';
import { writable } from 'svelte/store';
const keycloakUrl = import.meta.env.VITE_AUTH_SERVICE_URL;
const keycloakRealm = import.meta.env.VITE_AUTH_SERVICE_REALM;
const keycloakClientId = import.meta.env.VITE_AUTH_SERVICE_CLIENT_ID;
const keycloak = new Keycloak({
url: keycloakUrl,
realm: keycloakRealm,
clientId: keycloakClientId,
});
export const keycloakClientTokenStoreOnClient = writable({
authenticated: false,
token: null,
userGroups: [],
firstName: null,
lastName: null
});
export const initKeycloakOnClient = async () => {
try {
await keycloak.init({
checkLoginIframe: false,
onLoad: 'login-required',
});
if (keycloak.authenticated) {
await updateKeycloakStoreOnClient(); // performs keycloakClientTokenStoreOnClient.set ...
await storeKeycloakTokenOnServer(keycloak.token);
}
} catch (error) {
console.error('Keycloak initialization failed:', error);
}
Okay after ramming with this for several days I have to kindly ask the community.
I have a Svelte project, which integrates with Keycloak instance. All my keycloak functions are located in separate keycloakInteraction.ts
from which i reuse them.
My goal is: initialize the keycloak instance (enter login and password if previous session rotten or didn't exist) and then serve particular data based on obtained token.
The problem is that +layout.server.ts
that is serving data is executed prior to +layout.svelte that initializes keycloak, and while there is no token yet +layout.server.ts
serves empty array.
One of the workarounds is just to reload the page, so when the page is reset after user logged in, token is already in memory and data can be served.
However in my implementation the page won't automatically reset if the token has been expired and user has to relogin in the same window. I can't figure out how to workaround it with the variables. I also wonder if there are other graceful ways to login and then serve content based on user_group keycloak token property without reloading the page.
Any ideas will be much appreciated.
my +layout.svelte
:
<script>
import '../app.css';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import {
initKeycloakOnClient,
keycloakClientTokenStoreOnClient,
} from '$lib/keycloakInteraction';
export let data;
$: keycloakState = $keycloakClientTokenStoreOnClient;
$: isAuthenticated = keycloakState.authenticated;
onMount(async () => {
await initKeycloakOnClient();
hasReloaded = sessionStorage.getItem("hasReloadedAfterLogin");
if (isAuthenticated && !hasReloaded) {
console.log("User just logged in, reloading the page...");
sessionStorage.setItem("hasReloadedAfterLogin", "true");
location.reload();
}
});
</script>
{#if isAuthenticated}
<!--MENU HTML CODE IS HERE-->
{#each data.routes as route}
{/each}
<!--...and other data used provided by +layout.server.ts-->
<slot />
{:else}
<div class="h-screen flex justify-center items-center">
<p>Loading...</p>
</div>
{/if}
My +layout.server.ts
:
import type { LayoutServerLoad } from './$types';
import { selectAllClients, selectAllEngagements } from '$lib/server/database/queries';
import {
validateClientTokenOnServer,
resetKeycloakClientTokenStore
} from '$lib/keycloakInteractionResource';
import { keycloak } from '$lib/keycloakInteraction';
const routes = [
{
name: 'Link#1',
},
{
name: 'Link#2',
}
];
export const load: LayoutServerLoad = async ( request ) => {
let userGroup: string = null;
//getting clientToken from server-side cookies that were put by storeKeycloakTokenOnServer()
const clientToken = request.cookies.get('client_token');
if (clientToken) {
await validateClientTokenOnServer(clientToken);
const decodedToken = JSON.parse(atob(clientToken.split(".")[1]));
userGroup = decodedToken?.user_groups || [];
const availableData = await selectAllData(userGroup);
const availableRoutes = userGroup.includes("testGroup") ? routes.filter(route => route.name !== 'Link#2') : routes;
await resetKeycloakClientTokenStore();
return {
data: availableData,
routes: availableRoutes
}
}
}
My keycloakInteraction.ts
:
import Keycloak from 'keycloak-js';
import { writable } from 'svelte/store';
const keycloakUrl = import.meta.env.VITE_AUTH_SERVICE_URL;
const keycloakRealm = import.meta.env.VITE_AUTH_SERVICE_REALM;
const keycloakClientId = import.meta.env.VITE_AUTH_SERVICE_CLIENT_ID;
const keycloak = new Keycloak({
url: keycloakUrl,
realm: keycloakRealm,
clientId: keycloakClientId,
});
export const keycloakClientTokenStoreOnClient = writable({
authenticated: false,
token: null,
userGroups: [],
firstName: null,
lastName: null
});
export const initKeycloakOnClient = async () => {
try {
await keycloak.init({
checkLoginIframe: false,
onLoad: 'login-required',
});
if (keycloak.authenticated) {
await updateKeycloakStoreOnClient(); // performs keycloakClientTokenStoreOnClient.set ...
await storeKeycloakTokenOnServer(keycloak.token);
}
} catch (error) {
console.error('Keycloak initialization failed:', error);
}
Share
Improve this question
asked Feb 13 at 7:31
forkintheassforkintheass
777 bronze badges
1 Answer
Reset to default 1Return a flag by +layout.server.js
, check if it's true or false together with isAuthenticated, as it would mean that you are authenticated, but server part has not yet provided you data.
+layout.server.js
:
import type { LayoutServerLoad } from './$types';
import { selectAllClients, selectAllEngagements } from '$lib/server/database/queries';
import {
validateClientTokenOnServer,
resetKeycloakClientTokenStore
} from '$lib/keycloakInteractionResource';
import { keycloak } from '$lib/keycloakInteraction';
const routes = [
{
name: 'Link#1',
},
{
name: 'Link#2',
}
];
export const load: LayoutServerLoad = async ( request ) => {
let userGroup: string = null;
//getting clientToken from server-side cookies that were put by storeKeycloakTokenOnServer()
const clientToken = request.cookies.get('client_token');
if (!clientToken {
return {
tokenObtained: false
}
}
if (clientToken) {
await validateClientTokenOnServer(clientToken);
const decodedToken = JSON.parse(atob(clientToken.split(".")[1]));
userGroup = decodedToken?.user_groups || [];
const availableData = await selectAllData(userGroup);
const availableRoutes = userGroup.includes("testGroup") ? routes.filter(route => route.name !== 'Link#2') : routes;
await resetKeycloakClientTokenStore();
return {
tokenObtained: true,
data: availableData,
routes: availableRoutes
}
}
}
+layout.svelte
:
onMount(async () => {
await initKeycloakOnClient();
if (isAuthenticated && !data.tokenObtained) {
console.log("User just logged in, reloading the page...");
location.reload();
}
});
本文标签: Keycloak init in Svelte and then serve data according to the token propertiesStack Overflow
版权声明:本文标题:Keycloak init in Svelte and then serve data according to the token properties - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741558227a2385288.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论