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/core": "^2.0.0",
|
||||||
"@vuelidate/validators": "^2.0.0",
|
"@vuelidate/validators": "^2.0.0",
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
|
"keycloak-js": "^12.0.4",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
@@ -2766,6 +2768,11 @@
|
|||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"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": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
@@ -5863,6 +5870,11 @@
|
|||||||
"url": "https://opencollective.com/js-sdsl"
|
"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": {
|
"node_modules/js-tokens": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
@@ -5923,6 +5935,20 @@
|
|||||||
"node": ">=6"
|
"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": {
|
"node_modules/kleur": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"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": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
@@ -17,6 +17,8 @@
|
|||||||
"@vuelidate/core": "^2.0.0",
|
"@vuelidate/core": "^2.0.0",
|
||||||
"@vuelidate/validators": "^2.0.0",
|
"@vuelidate/validators": "^2.0.0",
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
|
"jwt-decode": "^3.1.2",
|
||||||
|
"keycloak-js": "^12.0.4",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-router": "^4.1.6",
|
"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 { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
||||||
import { faUserSecret } from '@fortawesome/free-solid-svg-icons'
|
import { faUserSecret } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
import './assets/main.css'
|
||||||
|
import AuthHelper from './authentication/AuthHelper'
|
||||||
|
|
||||||
/* add icons to the library */
|
/* add icons to the library */
|
||||||
library.add(faUserSecret)
|
library.add(faUserSecret)
|
||||||
|
|
||||||
import './assets/main.css'
|
|
||||||
|
|
||||||
const i18n = createI18n()
|
const i18n = createI18n()
|
||||||
|
|
||||||
const app = createApp(App)
|
let app = createApp(App)
|
||||||
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
|||||||
@@ -1,26 +1,58 @@
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import HomeView from '../views/HomeView.vue'
|
import HomeView from '../views/HomeView.vue'
|
||||||
|
import AuthHelper from '../authentication/AuthHelper'
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'main',
|
||||||
component: HomeView
|
component: HomeView,
|
||||||
|
meta: {
|
||||||
|
requiresAuth: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/about',
|
path: '/about',
|
||||||
name: 'about',
|
name: 'about',
|
||||||
// this page is lazy-loaded when the route is visited.
|
// 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(.*)*',
|
path: '/:pathMatch(.*)*',
|
||||||
name: 'notfound',
|
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
|
export default router
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { createStore } from 'vuex'
|
import { createStore } from 'vuex'
|
||||||
import moduleA from './moduleA.module'
|
import moduleA from './moduleA.module'
|
||||||
import moduleB from './moduleB.module'
|
import moduleB from './moduleB.module'
|
||||||
|
import keycloak from './keycloak.module'
|
||||||
|
|
||||||
export default createStore({
|
export default createStore({
|
||||||
modules: {
|
modules: {
|
||||||
|
keycloak: keycloak,
|
||||||
a: moduleA,
|
a: moduleA,
|
||||||
b: moduleB
|
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