implemented first keycloak stuff, still needs some config on keycloak and backend side to work
This commit is contained in:
26
src/App.vue
26
src/App.vue
@@ -1,9 +1,27 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router';
|
||||
import ProtectedData from './components/ProtectedData.vue';
|
||||
defineOptions({
|
||||
name: 'App'
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<img alt="Quasar logo" src="./assets/quasar-logo-vertical.svg" width="200vw"/>
|
||||
|
||||
<ProtectedData />
|
||||
</header>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
line-height: 1.5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-top: 7vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
40
src/components/ProtectedData.vue
Normal file
40
src/components/ProtectedData.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
import { useKeycloakStore } from '../stores/keycloakStore';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const protectedData = ref("");
|
||||
const keycloakStore = useKeycloakStore();
|
||||
|
||||
function fetchProtectedData() {
|
||||
const keycloak = keycloakStore.getKeycloak;
|
||||
if(!keycloak){
|
||||
return;
|
||||
}
|
||||
let myHeaders = new Headers();
|
||||
if(!keycloak.token){
|
||||
return;
|
||||
}
|
||||
myHeaders.append("Authorization", "Bearer " + keycloak.token);
|
||||
let requestOptons = {
|
||||
headers: myHeaders,
|
||||
};
|
||||
fetch("localhost:"+ import.meta.env.PORT_BACKEND + "/api/protected", requestOptons)
|
||||
.then((response) => response.text())
|
||||
.then((data) => {
|
||||
protectedData.value = data;
|
||||
console.info("Protected data: ", data);
|
||||
}).catch((e)=>console.error("Error fetching protected data: ", e));
|
||||
}
|
||||
onMounted(() => {
|
||||
console.info("Protected component mounted");
|
||||
fetchProtectedData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h3>Data: {{ protectedData }}</h3>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
<q-drawer
|
||||
v-model="leftDrawerOpen"
|
||||
show-if-above
|
||||
bordered
|
||||
>
|
||||
<q-list>
|
||||
|
||||
76
src/main.ts
Normal file
76
src/main.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import {createApp} from 'vue';
|
||||
import {createPinia} from 'pinia';
|
||||
|
||||
import App from './App.vue';
|
||||
|
||||
import Keycloak, {type KeycloakConfig, type KeycloakInitOptions} from 'keycloak-js';
|
||||
import { useKeycloakStore } from 'stores/keycloakStore';
|
||||
|
||||
const app = createApp(App);
|
||||
app.use(createPinia());
|
||||
|
||||
/**
|
||||
* Initialisierungsoptionen für Keycloak.
|
||||
* @param url URL zu Keycloak, Port definiert in keycloak_init.sh und quasar.config.js-Datei. Müssen identisch sein!
|
||||
* @param realm Name des Realms, hinterlegt in realm-export.json von Keycloak und quasar.config.js-Datei. Müssen identisch sein!
|
||||
* @param clientId Name des Clients, hinterlegt in realm-export.json von Keycloak und quasar.config.js-Datei. Müssen identisch sein!
|
||||
* @param onLoad = 'login-required': Hierdurch wird zum Aufrufen der ganzen Applikation ein login benötigt.
|
||||
* @param redirectUri: URL, zu der nach dem Login weitergeleitet wird. Hierbei wird die Port des Frontends aus der .env-Datei verwendet.
|
||||
*/
|
||||
|
||||
console.log("Keycloak Client ID: "+process.env.KEYCLOAK_CLIENT_ID);
|
||||
|
||||
const keycloakConfig: KeycloakConfig = {
|
||||
url: 'http://localhost:'+ process.env.PORT_KEYCLOAK as string+'/auth',
|
||||
realm: process.env.KEYCLOAK_REALM as string,
|
||||
clientId: process.env.KEYCLOAK_CLIENT_ID as string,
|
||||
};
|
||||
const initOptions: KeycloakInitOptions = {
|
||||
onLoad: 'login-required',
|
||||
redirectUri: 'http://localhost:8080/'//+ import.meta.env.PORT_FRONTEND as string +'/',
|
||||
};
|
||||
console.log(keycloakConfig);
|
||||
console.log(initOptions);
|
||||
const keycloak: Keycloak = new Keycloak(keycloakConfig);
|
||||
|
||||
const keycloakStore = useKeycloakStore();
|
||||
keycloakStore.setKeycloak(keycloak);
|
||||
|
||||
/**
|
||||
* Initialisierung von Keycloak.
|
||||
* Beginnt authentifizierungsprozess und lädt die Applikation neu, falls Authentifizierung fehlschlägt.
|
||||
* Weiterhin wird ein Tokenrefresh alle 70 Sekunden initialisiert.
|
||||
*/
|
||||
keycloak.init(initOptions).then((auth: boolean) => {
|
||||
if (!auth) {
|
||||
window.location.reload(); //Falls Authentifizierung fehlschlägt, wird die Seite neu geladen.
|
||||
} else {
|
||||
console.log('Authenticated'); //Loggt, dass Authentifizierung erfolgreich war.
|
||||
app.mount('#app'); //App wird geladen.
|
||||
if(keycloak.token) { //Überprüft, ob Token vorhanden ist.
|
||||
localStorage.setItem('vue-keycloak-token', keycloak.token); //Token wird in localStorage gespeichert, um es später auswerten zu können.
|
||||
}
|
||||
if(keycloak.refreshToken) { //Überprüft, ob Refresh-Token vorhanden ist.
|
||||
localStorage.setItem('vue-keycloak-refresh-token', keycloak.refreshToken); //Refresh-Token wird in localStorage gespeichert, um bei Ablauf des Tokens ein neues Token ohne erneute Authentifizierung zu erhalten.
|
||||
}
|
||||
}
|
||||
|
||||
//Token Refresh
|
||||
setInterval(() => {
|
||||
keycloak.updateToken(70).then((refreshed: boolean) => { //Token wird alle 70 Sekunden aktualisiert.
|
||||
if (refreshed) {
|
||||
console.log('Token refreshed');
|
||||
} else {
|
||||
console.warn('Token not refreshed');
|
||||
if(keycloak.tokenParsed && keycloak.tokenParsed.exp && keycloak.timeSkew){ //Fängt Probleme mit undefined Variablen ab
|
||||
console.log('Token is still valid for '
|
||||
+ Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds'); //Loggt, wie lange das Token noch gültig ist.
|
||||
}
|
||||
}
|
||||
}).catch(() => {
|
||||
console.error('Failed to refresh token'); //Loggt, dass Token nicht aktualisiert werden konnte.
|
||||
});
|
||||
}, 60000);
|
||||
}).catch((e) => {
|
||||
console.error('Authenticated Failed', e);
|
||||
});
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Todo, Meta } from 'components/models';
|
||||
import { Todo, Meta } from '../components/models';
|
||||
import ExampleComponent from 'components/ExampleComponent.vue';
|
||||
|
||||
defineOptions({
|
||||
|
||||
18
src/stores/keycloakStore.ts
Normal file
18
src/stores/keycloakStore.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type Keycloak from 'keycloak-js';
|
||||
import { defineStore } from 'pinia';
|
||||
//import api from 'axios';
|
||||
|
||||
export const useKeycloakStore = defineStore('keycloakStore', {
|
||||
state: ()=>({
|
||||
keycloak: null as Keycloak| null,
|
||||
}),
|
||||
getters: {
|
||||
getKeycloak: (state) => state.keycloak,
|
||||
},
|
||||
actions:{
|
||||
setKeycloak(keycloak: Keycloak): void {
|
||||
this.keycloak = keycloak;
|
||||
},
|
||||
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user