3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
||||
26
package-lock.json
generated
26
package-lock.json
generated
@@ -16,6 +16,8 @@
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"axios": "^1.2.2",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"keycloak-js": "^12.0.4",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
@@ -2766,6 +2768,11 @@
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
@@ -5863,6 +5870,11 @@
|
||||
"url": "https://opencollective.com/js-sdsl"
|
||||
}
|
||||
},
|
||||
"node_modules/js-sha256": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
|
||||
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@@ -5923,6 +5935,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jwt-decode": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
|
||||
"integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
|
||||
},
|
||||
"node_modules/keycloak-js": {
|
||||
"version": "12.0.4",
|
||||
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-12.0.4.tgz",
|
||||
"integrity": "sha512-O/BHtyiDrZrUnKBrVF8POojqd3gmhuiDw4FiI+FbnB14nu7G5jKFrKYZa9Q0JYKIZXHJOBzSaKQcMp2WUI+zmA==",
|
||||
"dependencies": {
|
||||
"base64-js": "1.3.1",
|
||||
"js-sha256": "0.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||
"lint": "eslint . --ext .vue,.ts,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||
@@ -17,6 +17,8 @@
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"axios": "^1.2.2",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"keycloak-js": "^12.0.4",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6",
|
||||
|
||||
7
public/silent-check-sso.html
Normal file
7
public/silent-check-sso.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
parent.postMessage(location.href, location.origin)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
42
src/authentication/AuthHelper.js
Normal file
42
src/authentication/AuthHelper.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import Keycloak from 'keycloak-js'
|
||||
|
||||
let keycloak = null
|
||||
|
||||
function setup() {
|
||||
keycloak = new Keycloak({
|
||||
url: 'https://auth.denysoft.eu/',
|
||||
realm: 'FST',
|
||||
clientId: 'frontend'
|
||||
})
|
||||
return keycloak
|
||||
.init({
|
||||
onLoad: 'login-required',
|
||||
checkLoginIframe: false
|
||||
})
|
||||
.then(function (authenticated) {
|
||||
setInterval(() => {
|
||||
keycloak
|
||||
.updateToken(90)
|
||||
.then(refreshed => {
|
||||
if (refreshed) {
|
||||
console.info('Token refreshed ' + refreshed)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Failed to refresh token')
|
||||
})
|
||||
}, 6000)
|
||||
})
|
||||
.catch(function () {
|
||||
alert('failed to initialize')
|
||||
})
|
||||
}
|
||||
function login() {
|
||||
keycloak.login()
|
||||
}
|
||||
|
||||
function getKeycloak() {
|
||||
return keycloak
|
||||
}
|
||||
|
||||
export default { setup, login, getKeycloak }
|
||||
5
src/components/ForbiddenPage.vue
Normal file
5
src/components/ForbiddenPage.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Forbidden!</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -7,14 +7,15 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||
import { faUserSecret } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import './assets/main.css'
|
||||
import AuthHelper from './authentication/AuthHelper'
|
||||
|
||||
/* add icons to the library */
|
||||
library.add(faUserSecret)
|
||||
|
||||
import './assets/main.css'
|
||||
|
||||
const i18n = createI18n()
|
||||
|
||||
const app = createApp(App)
|
||||
let app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
app.use(i18n)
|
||||
|
||||
@@ -1,26 +1,58 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import HomeView from '../views/HomeView.vue'
|
||||
import AuthHelper from '../authentication/AuthHelper'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: HomeView
|
||||
name: 'main',
|
||||
component: HomeView,
|
||||
meta: {
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
// this page is lazy-loaded when the route is visited.
|
||||
component: () => import('../views/AboutView.vue')
|
||||
component: () => import('../views/AboutView.vue'),
|
||||
meta: {
|
||||
requiresAuth: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/forbidden',
|
||||
name: 'forbidden',
|
||||
component: () => import('../components/ForbiddenPage.vue'),
|
||||
meta: {
|
||||
requiresAuth: false
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'notfound',
|
||||
component: () => import('../components/PageNotFound.vue')
|
||||
component: () => import('../components/PageNotFound.vue'),
|
||||
meta: {
|
||||
requiresAuth: false
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
router.beforeEach(async (to, from, next) => {
|
||||
if (to.meta.requiresAuth === true) {
|
||||
if (AuthHelper.getKeycloak() === null) {
|
||||
await AuthHelper.setup()
|
||||
}
|
||||
if (!AuthHelper.getKeycloak().authenticated) {
|
||||
next('/forbidden')
|
||||
}
|
||||
next()
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { createStore } from 'vuex'
|
||||
import moduleA from './moduleA.module'
|
||||
import moduleB from './moduleB.module'
|
||||
import keycloak from './keycloak.module'
|
||||
|
||||
export default createStore({
|
||||
modules: {
|
||||
keycloak: keycloak,
|
||||
a: moduleA,
|
||||
b: moduleB
|
||||
}
|
||||
|
||||
20
src/store/keycloak.module.js
Normal file
20
src/store/keycloak.module.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export default {
|
||||
state: () => ({
|
||||
keycloak: null
|
||||
}),
|
||||
mutations: {
|
||||
initKeycloak(state, data) {
|
||||
state.keycloak = data
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
initKeycloak({ commit }) {
|
||||
commit('initKeycloak')
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
getKeycloak(state) {
|
||||
return state.keycloak
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user