feat: use keycloak

This commit is contained in:
Ron 2025-05-22 23:28:32 +03:00
parent 867ba7746d
commit 89d8fbc843
9 changed files with 47 additions and 111 deletions

View File

@ -1,4 +1,4 @@
# Client Portal
# Portal
## Commands
@ -8,5 +8,5 @@
- Node.js
- Nuxt
- Directus
- Keycloak
- Vuetify

View File

@ -1,23 +0,0 @@
export const usePortalTags = () => {
const { fetchUser, setUser } = useDirectusAuth();
const user = useDirectusUser();
const tags = computed(() => (toValue(user)?.tags as Array<string>) || []);
const details = computed(() => {
const value = toValue(tags);
return {
interest: value.includes("portal-interest"),
};
});
onBeforeMount(async () => {
if (!user.value) {
const user = await fetchUser();
setUser(user.value);
}
});
return details;
};

View File

@ -1,14 +0,0 @@
export default defineNuxtRouteMiddleware(async () => {
const { fetchUser, setUser } = useDirectusAuth();
const user = useDirectusUser();
if (!user.value) {
const user = await fetchUser();
setUser(user.value);
}
if (!user.value) {
return navigateTo("/login");
}
});

View File

@ -1,13 +1,12 @@
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
modules: ["nuxt-directus", "vuetify-nuxt-module", "@vite-pwa/nuxt"],
modules: ["vuetify-nuxt-module", "@vite-pwa/nuxt"],
app: {
head: {
titleTemplate: "%s • Port Nimara Client Portal",
title: "Port Nimara Client Portal",
titleTemplate: "%s • Portal",
meta: [
{ property: "og:title", content: "Port Nimara Client Portal" },
{ property: "og:title", content: "Portal" },
{ property: "og:image", content: "/og-image.png" },
{ name: "twitter:card", content: "summary_large_image" },
],
@ -18,17 +17,19 @@ export default defineNuxtConfig({
},
runtimeConfig: {
public: {
directus: {
url: "https://cms.portnimara.dev",
keycloak: {
url: "",
realm: "",
clientId: "",
},
},
},
vuetify: {
vuetifyOptions: {
theme: {
defaultTheme: "portnimara",
defaultTheme: "portal",
themes: {
portnimara: {
portal: {
colors: {
primary: "#387bca",
},

17
package-lock.json generated
View File

@ -7,8 +7,8 @@
"hasInstallScript": true,
"dependencies": {
"@vite-pwa/nuxt": "^0.10.6",
"keycloak-js": "^26.2.0",
"nuxt": "^3.15.4",
"nuxt-directus": "^5.7.0",
"vue": "latest",
"vue-router": "latest",
"vuetify-nuxt-module": "^0.18.3"
@ -8268,6 +8268,12 @@
"node": ">=0.10.0"
}
},
"node_modules/keycloak-js": {
"version": "26.2.0",
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.0.tgz",
"integrity": "sha512-CrFcXTN+d6J0V/1v3Zpioys6qHNWE6yUzVVIsCUAmFn9H14GZ0vuYod+lt+SSpMgWGPuneDZBSGBAeLBFuqjsw==",
"license": "Apache-2.0"
},
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@ -9159,15 +9165,6 @@
}
}
},
"node_modules/nuxt-directus": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/nuxt-directus/-/nuxt-directus-5.7.0.tgz",
"integrity": "sha512-hoNXbhQ8UgDrCXqzqxC0wngi64AVqYYGGU/bwylgZWbKyU0m6kyNQVLGuQuXmFbogr2WMaw+FtXSgLz+DS32hA==",
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.0.0"
}
},
"node_modules/nypm": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/nypm/-/nypm-0.5.2.tgz",

View File

@ -9,8 +9,8 @@
},
"dependencies": {
"@vite-pwa/nuxt": "^0.10.6",
"keycloak-js": "^26.2.0",
"nuxt": "^3.15.4",
"nuxt-directus": "^5.7.0",
"vue": "latest",
"vue-router": "latest",
"vuetify-nuxt-module": "^0.18.3"

View File

@ -1,35 +1,17 @@
<template>
<v-app full-height>
<v-navigation-drawer
v-model="drawer"
:location="mdAndDown ? 'bottom' : undefined"
>
<v-navigation-drawer v-model="drawer" :location="mdAndDown ? 'bottom' : undefined">
<v-img v-if="!mdAndDown" src="/logo.jpg" height="75" class="my-6" />
<v-list color="primary" lines="two">
<v-list-item
v-for="(item, index) in menu"
:key="index"
:to="item.to"
:title="item.title"
:prepend-icon="item.icon"
/>
<v-list-item v-for="(item, index) in menu" :key="index" :to="item.to" :title="item.title"
:prepend-icon="item.icon" />
</v-list>
<template #append>
<v-list lines="two">
<v-list-item
v-if="user"
:title="`${user.first_name} ${user.last_name}`"
:subtitle="user.email"
prepend-icon="mdi-account"
/>
<v-list-item
@click="logOut"
title="Log out"
prepend-icon="mdi-logout"
base-color="error"
/>
<v-list-item title="Logged in" prepend-icon="mdi-account" />
<v-list-item @click="logOut" title="Log out" prepend-icon="mdi-logout" base-color="error" />
</v-list>
</template>
</v-navigation-drawer>
@ -42,13 +24,7 @@
<v-img src="/logo.jpg" height="50" />
<template #append>
<v-btn
@click="logOut"
class="mr-3"
variant="text"
color="error"
icon="mdi-logout"
/>
<v-btn @click="logOut" class="mr-3" variant="text" color="error" icon="mdi-logout" />
</template>
</v-app-bar>
@ -60,18 +36,14 @@
<script setup>
definePageMeta({
middleware: ["authentication"],
layout: false,
});
const { mdAndDown } = useDisplay();
const { logout } = useDirectusAuth();
const user = useDirectusUser();
const tags = usePortalTags();
const drawer = ref(false);
const interestMenu = [
const menu = ref([
{
to: "/dashboard/interest-eoi-queue",
icon: "mdi-tray-full",
@ -102,11 +74,6 @@ const interestMenu = [
icon: "mdi-account-check",
title: "Interest Status",
},
];
const defaultMenu = [
{
to: "/dashboard/site",
icon: "mdi-view-dashboard",
@ -117,14 +84,9 @@ const defaultMenu = [
icon: "mdi-finance",
title: "Data Analytics",
},
];
const menu = computed(() =>
toValue(tags).interest ? interestMenu : defaultMenu
);
]);
const logOut = async () => {
await logout();
return navigateTo("/login");
};

View File

@ -1,9 +1,3 @@
<script lang="ts" setup>
const tags = usePortalTags();
onBeforeMount(() =>
navigateTo(
toValue(tags).interest ? "/dashboard/interest-analytics" : "/dashboard/site"
)
);
onBeforeMount(() => navigateTo("/dashboard/interest-analytics"));
</script>

View File

@ -0,0 +1,19 @@
import Keycloak from "keycloak-js";
export default defineNuxtPlugin((application) => {
const runtimeConfig = useRuntimeConfig();
const keycloak = new Keycloak({
url: runtimeConfig.public.keycloak.url,
realm: runtimeConfig.public.keycloak.realm,
clientId: runtimeConfig.public.keycloak.clientId,
});
keycloak.init({
onLoad: "login-required",
});
keycloak.updateToken(2000);
application.$keycloak = keycloak;
});