keycloak fix

This commit is contained in:
2025-07-01 13:45:20 +07:00
parent 1532ef6db8
commit 78b75999ea
13 changed files with 235 additions and 71 deletions
+33 -33
View File
@@ -1,52 +1,52 @@
// project imports
import mock from './mockAdapter';
import type { notificationType, profileType, languageType, appsLinkType,searchType } from '@/types/HeaderTypes'
import type { notificationType, profileType, languageType, appsLinkType, searchType } from '@/types/HeaderTypes'
//
// Notification
//
const notifications:notificationType[] = [
const notifications: notificationType[] = [
{
avatar: 'widget-3-line-duotone',
color:'error',
color: 'error',
title: 'Launch Admin',
subtitle: 'Just see the my new admin!',
time:'9:30 AM'
time: '9:30 AM'
},
{
avatar: 'calendar-line-duotone',
color:'primary',
color: 'primary',
title: 'Event Today',
subtitle: 'Just a reminder that you have event',
time:'9:15 AM'
time: '9:15 AM'
},
{
avatar: 'settings-line-duotone',
color:'secondary',
color: 'secondary',
title: 'Settings',
subtitle: 'You can customize this template as you want',
time:'4:36 PM'
time: '4:36 PM'
},
{
avatar: 'widget-4-line-duotone',
color:'warning',
color: 'warning',
title: 'Launch Admin',
subtitle: 'Just see the my new admin!',
time:'9:30 AM'
time: '9:30 AM'
},
{
avatar: 'calendar-line-duotone',
color:'primary',
color: 'primary',
title: 'Event Today',
subtitle: 'Just a reminder that you have event',
time:'9:15 AM'
time: '9:15 AM'
},
{
avatar: 'settings-line-duotone',
color:'secondary',
color: 'secondary',
title: 'Settings',
subtitle: 'You can customize this template as you want',
time:'4:36 PM'
time: '4:36 PM'
},
];
@@ -57,29 +57,29 @@ const profileDD: profileType[] = [
{
title: 'My Profile',
href: '/apps/user/profile',
badge:false
badge: false
},
{
title: 'My Subscription',
href: '/pages/pricing',
badge:false
badge: false
},
{
title: 'My Notes',
href: '/apps/notes',
badge:true
badge: true
},
{
title: 'Account Settings',
href: '/pages/account-settings',
badge:false
badge: false
},
{
title: 'Sign Out',
href: '/auth/login2',
badge:false
},
// {
// title: 'Sign Out',
// href: '/auth/login2',
// badge:false
// },
];
//
@@ -102,57 +102,57 @@ const languageDD: languageType[] = [
const appsLink: appsLinkType[] = [
{
avatar: 'chat-line-bold-duotone',
color:'primary',
color: 'primary',
title: 'Chat Application',
subtext: 'New messages arrived',
href: '/apps/chats'
},
{
avatar: 'user-bold-duotone',
color:'success',
color: 'success',
title: 'User Profile App',
subtext: 'Get profile details',
href: '/apps/user/profile'
},
{
avatar: 'bill-list-bold-duotone',
color:'secondary',
color: 'secondary',
title: 'eCommerce App',
subtext: 'learn more information',
href: '/ecommerce/products'
},
{
avatar: 'calendar-minimalistic-bold-duotone',
color:'primary',
color: 'primary',
title: 'Calendar App',
subtext: 'Get dates',
href: '/apps/calendar'
},
{
avatar: 'phone-calling-rounded-bold-duotone',
color:'warning',
color: 'warning',
title: 'Contact Application',
subtext: '2 Unsaved Contacts',
href: '/apps/contacts'
},
{
avatar: 'settings-bold-duotone',
color:'info',
color: 'info',
title: 'Account Setting App',
subtext: 'Account settings',
href: '/pages/account-settings'
},
{
avatar: 'checklist-minimalistic-bold',
color:'error',
color: 'error',
title: 'Kanban App',
subtext: 'Get new Task',
href: '/apps/kanban'
},
{
avatar: 'notes-bold-duotone',
color:'warning',
color: 'warning',
title: 'Notes Application',
subtext: 'To-do and Daily tasks',
href: '/apps/notes'
+3 -1
View File
@@ -59,7 +59,9 @@ const login = () => {
</RouterLink>
</div>
</div>
<v-btn size="large" color="primary" :disabled="valid" block flat @click="login">Sign In</v-btn>
<!-- <v-btn size="large" color="primary" :disabled="valid" block flat @click="login">Sign In</v-btn> -->
<v-btn v-for="provider in providers" :key="provider" @click="signIn(provider.id)" color="primary" size="large"
block flat>Sign in with {{ provider.name }}</v-btn>
<!-- <div class="mt-2">
<v-alert color="error"></v-alert>
</div> -->
@@ -1,5 +1,15 @@
<script setup lang="ts">
import { signOut } from "next-auth/react";
import { profileDD } from "@/_mockApis/headerData";
const { data, status, getCsrfToken, getProviders } = useAuth()
const runtimeConfig = useRuntimeConfig()
const logout = async () => {
await signOut()
const LogOutKeycloakURL = `${runtimeConfig.public.keycloakUrl}/realms/${runtimeConfig.public.keycloakRealm}/protocol/openid-connect`
const logOutURL = `${LogOutKeycloakURL}/logout?client_id=${runtimeConfig.public.keycloakClient}&post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}/auth/login`;
window.location.href = logOutURL
}
</script>
<template>
@@ -8,19 +18,9 @@ import { profileDD } from "@/_mockApis/headerData";
<!-- ---------------------------------------------- -->
<v-menu open-on-hover open-on-click>
<template v-slot:activator="{ props }">
<v-btn
variant="text"
class="custom-hover-primary"
color="primary"
v-bind="props"
icon
>
<v-btn variant="text" class="custom-hover-primary" color="primary" v-bind="props" icon>
<v-avatar size="35">
<img
src="@/assets/images/profile/user-1.jpg"
width="35"
alt="Julia"
/>
<img src="@/assets/images/profile/user-1.jpg" width="35" alt="Julia" />
</v-avatar>
</v-btn>
</template>
@@ -34,30 +34,23 @@ import { profileDD } from "@/_mockApis/headerData";
<h6 class="text-subtitle-1">
David McMichael <span class="text-success text-caption">Pro</span>
</h6>
<span class="text-subtitle-1 textSecondary"
>david@wrappixel.com</span
>
<span class="text-subtitle-1 textSecondary">david@wrappixel.com</span>
</div>
</div>
<v-divider></v-divider>
<perfect-scrollbar
style="height: calc(100vh - 240px); max-height: 240px"
>
<perfect-scrollbar style="height: calc(100vh - 240px); max-height: 240px">
<v-list class="py-0 theme-list mt-3" lines="one">
<v-list-item
v-for="item in profileDD"
:key="item.title"
class="py-0 px-2 rounded-md custom-text-primary"
color="primary"
:to="item.href"
>
<v-list-item v-for="item in profileDD" :key="item.title" class="py-0 px-2 rounded-md custom-text-primary"
color="primary" :to="item.href">
<div class="d-flex gap-3 align-center">
<p class="text-subtitle-1 heading custom-title">
{{ item.title }}
</p>
<v-chip size="small" color="error" v-if="item.badge">4</v-chip>
</div>
</v-list-item>
<v-btn @click="logout" color="primary" variant="outlined" block>Logout</v-btn>
</v-list>
</perfect-scrollbar>
</div>
@@ -0,0 +1,4 @@
export const useUseGetUserLoginComposables = (data: any) => {
console.log('data useUseGetUserLoginComposables', data)
return data;
}
+12
View File
@@ -0,0 +1,12 @@
const userInfoStores = useUserInfoStore()
const { getUserInfoStore } = storeToRefs(useUserInfoStore())
const { data } = useAuth()
export default defineNuxtRouteMiddleware((to, from) => {
console.log(data.value)
if (data.value === null || !data.value) {
navigateTo('/sample-page')
} else {
navigateTo('/sambelPage_copy')
console.log('berhasil login')
}
})
+10 -10
View File
@@ -103,16 +103,16 @@ export default defineNuxtConfig({
keycloakRealm: process.env.KEYCLOAK_REALM,
}
},
// auth: {
// isEnabled: true,
// baseURL: process.env.AUTH_ORIGIN,
// provider: {
// type: "authjs",
// },
// globalAppMiddleware: {
// isEnabled: true,
// },
// },
auth: {
isEnabled: true,
baseURL: process.env.AUTH_ORIGIN,
provider: {
type: "authjs",
},
globalAppMiddleware: {
isEnabled: true,
},
},
devServerHandlers: [],
hooks: {},
+44
View File
@@ -0,0 +1,44 @@
<script setup lang="ts">
definePageMeta({
middleware: ['auth']
})
import { ref } from "vue";
import UiParentCard from "@/components/shared/UiParentCard.vue";
import { useAuth, useUserInfoStore } from "#imports";
import { useUseGetUserLoginComposables } from "~/composables/useGetUserLoginComposables"
const { setUserInfoStore } = useUserInfoStore();
const { getUserInfoStore } = storeToRefs(useUserInfoStore());
const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth()
const tokens = ref('')
onMounted(async () => {
// $fetch(`/api/auth/protected`).then(res => console.log('ini responnya',res))
const headers = useRequestHeaders(['cookie']) as HeadersInit
const { data: token } = await useFetch('/api/token', { headers })
tokens.value = token.value
// userAuthenticate(token.value)
setUserInfoStore(token.value)
})
const getUserFromComposable = () => {
const a = useUseGetUserLoginComposables(getUserInfoStore.value)
console.log('ini a', a)
}
</script>
<template>
<v-row>
<v-col cols="12" md="12">
<v-card elevation="10">
<v-card-item>
<!-- <pre><span>Providers:</span> {{ getUserInfoStore }}</pre> -->
<h5 class="text-h5 mb-3">Sample Page</h5>
<p class="text-body-1">This is a sample page</p>
<div class="mt-4">
<!-- <v-btn @click="getUserFromComposable" color="primary" variant="outlined" block>useComposables</v-btn> -->
<!-- <pre><span>Providers:</span> {{ tokens }}</pre> -->
</div>
</v-card-item>
</v-card>
</v-col>
</v-row>
</template>
+29 -1
View File
@@ -1,14 +1,42 @@
<script setup lang="ts">
definePageMeta({
middleware: ['auth']
})
import { ref } from "vue";
import UiParentCard from "@/components/shared/UiParentCard.vue";
import { useAuth, useUserInfoStore } from "#imports";
import { useUseGetUserLoginComposables } from "~/composables/useGetUserLoginComposables"
const { setUserInfoStore } = useUserInfoStore();
const { getUserInfoStore } = storeToRefs(useUserInfoStore());
const { data, status, getCsrfToken, getProviders, signOut, getSession } = useAuth()
const tokens = ref('')
onMounted(async () => {
// $fetch(`/api/auth/protected`).then(res => console.log('ini responnya',res))
const headers = useRequestHeaders(['cookie']) as HeadersInit
const { data: token } = await useFetch('/api/token', { headers })
tokens.value = token.value
// userAuthenticate(token.value)
setUserInfoStore(token.value)
})
const getUserFromComposable = () => {
const a = useUseGetUserLoginComposables(getUserInfoStore.value)
console.log('ini a', a)
}
</script>
<template>
<v-row>
<v-col cols="12" md="12">
<v-card elevation="10">
<v-card-item>
<h5 class="text-h5 mb-3">Sample Page</h5>
<pre><span>Providers:</span> {{ getUserInfoStore }}</pre>
<h5 class="text-h5 mb-3">Sample Page</h5>
<p class="text-body-1">This is a sample page</p>
<div class="mt-4">
<v-btn @click="getUserFromComposable" color="primary" variant="outlined" block>useComposables</v-btn>
<!-- <pre><span>Providers:</span> {{ tokens }}</pre> -->
</div>
</v-card-item>
</v-card>
</v-col>
+8 -1
View File
@@ -1,7 +1,14 @@
<script setup lang="ts">
/*-For Set Blank Layout-*/
// definePageMeta({
// layout: "blank",
// });
definePageMeta({
layout: "blank",
layout: "auth",
auth: {
unauthenticatedOnly: true,
navigateAuthenticatedTo: '/sample-page',
},
});
</script>
<template>
+10
View File
@@ -0,0 +1,10 @@
import { getServerSession, getToken } from '#auth'
export default eventHandler(async (event) => {
const session = await getServerSession(event)
if (!session) {
return { status: 'unauthenticated!' }
}
const token = await getToken({ event })
return token || { status: 'no token present' }
})
+38
View File
@@ -0,0 +1,38 @@
import { defineStore } from "pinia";
import { timestampToDate } from "~/utils/helper";
export const useUserInfoStore = defineStore("userInfoStore", () => {
const getUserInfoStore = ref<any>([])
const setUserInfoStore = (data: any) => {
const userInfo: any[] =
{
user_name: data?.access_token_payload?.preferred_username,
type_user: data?.access_token_payload?.type_user,
role_access: data?.access_token_payload?.resource_access[data?.access_token_payload.azp],
userInfo: [
{
id: data?.user?.id,
fullname: data?.access_token_payload?.name,
given_name: data?.access_token_payload?.given_name || '-',
family_name: data?.access_token_payload?.family_name || '-',
email: data?.access_token_payload?.email || '- ',
group: data?.access_token_payload?.group,
}
],
expires_in: [
{
timestamps: data?.expires_at,
date: timestampToDate(data?.expires_at, 'id-ID'),
}
],
};
// console.log(data)
getUserInfoStore.value = userInfo;
}
const getMenuAkses = ref<any>([])
// const
return { setUserInfoStore, getUserInfoStore }
})
+26
View File
@@ -0,0 +1,26 @@
export function capitalizeEachWord(text: string) {
// const lowercase = text.toLowerCase();
// return lowercase.charAt(0).toUpperCase() + lowercase.slice(1);
return text
.toLowerCase()
.split(' ')
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
}
export function timestampToDate(timestamp: number, locale: string, options = {}) {
const date = new Date(timestamp * 1000);
// locale forma --> `id-ID`
return date.toLocaleString(locale, {
// timeZone: options.timeZone,
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short',
...options
});
}