Skip to content
Toggle navigation
Projects
Groups
Snippets
Help
dtd
/
civitas.ui
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit fb62f636
authored
Apr 24, 2025
by
Samuel Taniel Mulyadi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add token expired
1 parent
d7205995
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
126 additions
and
4 deletions
@core/scss/template/pages/page-auth.scss
@core/stores/keycloakStore.ts
layouts/components/DefaultLayoutWithHorizontalNav.vue
layouts/components/DefaultLayoutWithVerticalNav.vue
layouts/components/NavbarTokenExpiredTime.vue
plugins/keycloak.ts
views/dstipro/beranda/keamanan/index.vue
@core/scss/template/pages/page-auth.scss
View file @
fb62f63
...
...
@@ -75,7 +75,7 @@
min-block-size
:
100vh
;
/* Ensures the element covers the full viewport height */
padding-block-start
:
10px
;
// margin: 5% 5%;marginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmargin
// margin: 5% 5%;marginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmarginmargin
margin
}
.main-component-margin
{
...
...
@core/stores/keycloakStore.ts
View file @
fb62f63
...
...
@@ -13,6 +13,7 @@ const username = ref<string>('')
const
civitas
=
ref
<
string
>
(
''
)
const
kodeIdentitas
=
ref
<
string
>
(
''
)
const
accessToken
=
ref
<
string
>
(
''
)
const
tokenParsedExp
=
ref
<
number
>
(
0
)
const
refreshTokenExp
=
ref
<
number
>
(
0
)
const
roles
=
ref
<
string
[]
>
([])
const
selectedRole
=
useStorage
(
'selectedRole'
,
'admin'
)
...
...
@@ -28,6 +29,7 @@ const refresh = (): void => {
username
.
value
=
tokenParsed
.
preferred_username
||
''
civitas
.
value
=
tokenParsed
.
civitas
||
''
kodeIdentitas
.
value
=
tokenParsed
.
kodeIdentitas
||
''
tokenParsedExp
.
value
=
tokenParsed
.
exp
||
0
accessToken
.
value
=
keycloakInstance
.
token
||
''
refreshTokenExp
.
value
=
refreshedTokenParsed
.
exp
||
0
roles
.
value
=
keycloakInstance
.
resourceAccess
?.
vueplayground
?.
roles
??
[]
...
...
layouts/components/DefaultLayoutWithHorizontalNav.vue
View file @
fb62f63
<
script
lang=
"ts"
setup
>
import
{
HorizontalNavLayout
}
from
'@layouts'
import
navItems
from
'@/navigation/horizontal'
import
{
computed
,
onMounted
,
onUnmounted
,
ref
}
from
'vue'
import
{
useKeycloakStore
}
from
'@/@core/stores/keycloakStore'
import
keycloakInstance
from
'@/keycloak'
// Components
import
Footer
from
'@/layouts/components/Footer.vue'
import
NavbarThemeSwitcher
from
'@/layouts/components/NavbarThemeSwitcher.vue'
import
NavbarTokenExpiredTime
from
'@/layouts/components/NavbarTokenExpiredTime.vue'
import
UserProfile
from
'@/layouts/components/UserProfile.vue'
import
navItems
from
'@/navigation/horizontal'
// Keycloak & state
const
keycloakStore
=
useKeycloakStore
()
const
authenticated
=
computed
(()
=>
keycloakStore
.
authenticated
)
const
now
=
ref
(
Math
.
floor
(
Date
.
now
()
/
1000
))
const
tokenLifetime
=
ref
(
0
)
let
timer
:
ReturnType
<
typeof
setInterval
>
onMounted
(()
=>
{
// Set tokenLifetime only once on mount
if
(
keycloakInstance
.
tokenParsed
?.
exp
&&
keycloakInstance
.
tokenParsed
?.
iat
)
tokenLifetime
.
value
=
keycloakInstance
.
tokenParsed
.
exp
-
keycloakInstance
.
tokenParsed
.
iat
// Start timer
timer
=
setInterval
(()
=>
{
now
.
value
=
Math
.
floor
(
Date
.
now
()
/
1000
)
},
1000
)
})
onUnmounted
(()
=>
{
clearInterval
(
timer
)
})
// Computed expiration values
const
computedExpIn
=
computed
(()
=>
{
return
authenticated
.
value
&&
keycloakInstance
.
tokenParsed
?.
exp
?
Math
.
max
(
keycloakInstance
.
tokenParsed
?.
exp
-
now
.
value
,
0
)
:
0
})
</
script
>
<
template
>
...
...
@@ -39,10 +73,27 @@ import UserProfile from '@/layouts/components/UserProfile.vue'
:languages=
"themeConfig.app.i18n.langConfig"
/>
-->
<NavbarTokenExpiredTime
/>
<NavbarThemeSwitcher
/>
<!--
<NavbarShortcuts
/>
-->
<!--
<NavBarNotifications
class=
"me-2"
/>
-->
<!--
<div
class=
"pa-4"
>
<VAlert
v-if=
"authenticated"
type=
"info"
border=
"start"
variant=
"outlined"
class=
"mb-4"
>
<h3
class=
"text-h6 font-weight-bold"
>
Access token expires in
{{
computedExpIn
}}
sec,
Refresh token in
{{
computedRefExpIn
}}
sec,
Session:
{{
computedSessionTimer
}}
</h3>
</VAlert>
</div>
-->
<UserProfile
/>
</
template
>
...
...
layouts/components/DefaultLayoutWithVerticalNav.vue
View file @
fb62f63
...
...
@@ -5,6 +5,7 @@ import navItems from '@/navigation/vertical'
// Components
import
Footer
from
'@/layouts/components/Footer.vue'
import
NavbarThemeSwitcher
from
'@/layouts/components/NavbarThemeSwitcher.vue'
import
NavbarTokenExpiredTime
from
'@/layouts/components/NavbarTokenExpiredTime.vue'
import
UserProfile
from
'@/layouts/components/UserProfile.vue'
// @layouts plugin
...
...
@@ -41,6 +42,7 @@ import UserProfile from '@/layouts/components/UserProfile.vue'
:languages=
"themeConfig.app.i18n.langConfig"
/>
-->
<NavbarTokenExpiredTime
/>
<NavbarThemeSwitcher
/>
<!--
<NavbarShortcuts
/>
-->
<!--
<NavBarNotifications
class=
"me-2"
/>
-->
...
...
layouts/components/NavbarTokenExpiredTime.vue
0 → 100644
View file @
fb62f63
<
script
setup
lang=
"ts"
>
import
{
computed
,
onMounted
,
onUnmounted
,
ref
}
from
'vue'
import
{
useKeycloakStore
}
from
'@/@core/stores/keycloakStore'
import
keycloakInstance
from
'@/keycloak'
const
keycloakStore
=
useKeycloakStore
()
const
authenticated
=
computed
(()
=>
keycloakStore
.
authenticated
)
const
now
=
ref
(
Math
.
floor
(
Date
.
now
()
/
1000
))
const
tokenLifetime
=
ref
(
0
)
let
timer
:
ReturnType
<
typeof
setInterval
>
onMounted
(()
=>
{
// Set tokenLifetime only once
if
(
keycloakInstance
.
tokenParsed
?.
exp
&&
keycloakInstance
.
tokenParsed
?.
iat
)
tokenLifetime
.
value
=
keycloakInstance
.
tokenParsed
.
exp
-
keycloakInstance
.
tokenParsed
.
iat
timer
=
setInterval
(()
=>
{
now
.
value
=
Math
.
floor
(
Date
.
now
()
/
1000
)
},
1000
)
})
onUnmounted
(()
=>
{
clearInterval
(
timer
)
})
const
computedExpIn
=
computed
(()
=>
{
return
authenticated
.
value
&&
keycloakInstance
.
tokenParsed
?.
exp
?
Math
.
max
(
keycloakInstance
.
tokenParsed
.
exp
-
now
.
value
,
0
)
:
0
})
</
script
>
<
template
>
<div
v-if=
"authenticated"
class=
"me-4"
style=
"position: relative; block-size: 40px; inline-size: 40px;"
>
<VProgressCircular
:model-value=
"(computedExpIn / tokenLifetime) * 100"
:size=
"40"
:width=
"3"
color=
"primary"
/>
<div
class=
"text-subtitle-1 font-weight-bold"
style=
"position: absolute; inset-block-start: 50%; inset-inline-start: 50%; transform: translate(-50%, -50%);"
>
{{
computedExpIn
}}
</div>
</div>
</
template
>
plugins/keycloak.ts
View file @
fb62f63
...
...
@@ -15,6 +15,19 @@ export default defineNuxtPlugin(async nuxtApp => {
keycloakStore
.
refresh
()
console
.
log
(
'User is authenticated'
)
navigateTo
(
'/profile'
)
setInterval
(()
=>
{
const
now
=
Math
.
floor
(
Date
.
now
()
/
1000
)
const
tokenExp
=
keycloakInstance
.
tokenParsed
?.
exp
??
0
if
(
tokenExp
<=
now
)
{
console
.
warn
(
'Token expired. Logging out...'
)
keycloakInstance
.
logout
({
redirectUri
:
`
${
window
.
location
.
origin
}
/login`
})
}
else
{
console
.
log
(
'Token expires in:'
,
tokenExp
-
now
,
'seconds'
)
}
},
10
_000
)
}
else
{
console
.
log
(
'User is not authenticated'
)
...
...
views/dstipro/beranda/keamanan/index.vue
View file @
fb62f63
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
Attach a file
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to post a comment