added logout function and persistent pinia store
This commit is contained in:
13
src/App.vue
13
src/App.vue
@@ -1,17 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { RouterView } from 'vue-router';
|
import { defineComponent } from 'vue';
|
||||||
import ProtectedData from './components/ProtectedData.vue';
|
|
||||||
defineOptions({
|
export default defineComponent({
|
||||||
name: 'App'
|
name: 'App'
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<header>
|
|
||||||
<img alt="Quasar logo" src="./assets/quasar-logo-vertical.svg" width="200vw"/>
|
|
||||||
|
|
||||||
<ProtectedData />
|
|
||||||
</header>
|
|
||||||
<router-view />
|
<router-view />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
6
src/boot/pinia.ts
Normal file
6
src/boot/pinia.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { boot } from 'quasar/wrappers';
|
||||||
|
import { createPinia } from 'pinia';
|
||||||
|
|
||||||
|
export default boot(({ app }) => {
|
||||||
|
app.use(createPinia());
|
||||||
|
});
|
||||||
@@ -1,50 +1,29 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
//import { useKeycloakStore } from '../stores/keycloakStore';
|
import { defineComponent, onMounted, ref } from 'vue';
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import { useUserStore } from 'stores/user-store';
|
import { useUserStore } from 'stores/user-store';
|
||||||
import { useKeycloakStore } from 'stores/keycloakStore';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
/*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();
|
|
||||||
});*/
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'ProtectedData',
|
name: 'ProtectedData',
|
||||||
components: {},
|
components: {},
|
||||||
methods: {
|
|
||||||
logout() {
|
|
||||||
const keycloakStore = useKeycloakStore();
|
|
||||||
keycloakStore.logout();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup() {
|
setup() {
|
||||||
return useUserStore();
|
const userStore = useUserStore();
|
||||||
},
|
const router = useRouter();
|
||||||
|
|
||||||
|
const user = ref();
|
||||||
|
const userLoaded = ref(false);
|
||||||
|
const logout = () => {
|
||||||
|
userStore.logout();
|
||||||
|
router.push('/');
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
console.log("IM MOUNTEEED: " + userStore.userLoaded + " " + userStore.user)
|
||||||
|
userLoaded.value = userStore.userLoaded;
|
||||||
|
user.value = userStore.user;
|
||||||
|
return { user, userLoaded };
|
||||||
|
});
|
||||||
|
return { user, userLoaded, logout };
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -57,7 +36,7 @@ export default defineComponent({
|
|||||||
<p>{{ user.username }}</p>
|
<p>{{ user.username }}</p>
|
||||||
<p>{{ user.keycloakID }}</p>
|
<p>{{ user.keycloakID }}</p>
|
||||||
</div>
|
</div>
|
||||||
<q-btn @click="logout()" label="Logout" />
|
<q-btn @click="logout()" label="Logout"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
54
src/main.ts
54
src/main.ts
@@ -4,69 +4,31 @@ import {createPinia} from 'pinia';
|
|||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
import Keycloak from 'keycloak-js';
|
import Keycloak from 'keycloak-js';
|
||||||
import { useKeycloakStore } from 'stores/keycloakStore';
|
|
||||||
import {useUserStore} from 'stores/user-store';
|
import {useUserStore} from 'stores/user-store';
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(createPinia());
|
const pinia = createPinia();
|
||||||
|
app.use(pinia);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Variablen sind in quasar.config.js definiert und werden hier verwendet.
|
|
||||||
* @param keycloakPort Port, auf dem Keycloak läuft, hinterlegt in docker-compose.yml
|
|
||||||
* @param frontendPort Port, auf dem das Frontend läuft, hinterlegt in quasar.config.js und realm-export.json von Keycloak für die Redirect-URL
|
|
||||||
* @param realm Name des Realms, hinterlegt in realm-export.json von Keycloak
|
|
||||||
* @param clientId Name des Clients, hinterlegt in realm-export.json von Keycloak
|
|
||||||
*/
|
|
||||||
const keycloakPort = "" + process.env.PORT_KEYCLOAK;
|
|
||||||
const frontendPort = "" + process.env.PORT_FRONTEND;
|
|
||||||
const realm = "" + process.env.KEYCLOAK_REALM;
|
|
||||||
const clientId = "" + process.env.KEYCLOAK_CLIENT_ID;
|
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const keycloakStore = useKeycloakStore();
|
const keycloak: Keycloak = await userStore.initKeycloak();
|
||||||
|
|
||||||
const keycloak = new Keycloak({
|
|
||||||
url: 'http://localhost:' + keycloakPort + '/',
|
|
||||||
realm: realm,
|
|
||||||
clientId: clientId
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
await keycloak.init({
|
|
||||||
onLoad: 'login-required', //authentifizierung erforderlich
|
|
||||||
redirectUri: 'http://localhost:' + frontendPort + '/test/'
|
|
||||||
}).then( (auth) => {
|
|
||||||
console.log("Authenticated: " + auth);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(keycloak);
|
|
||||||
console.log(keycloak.subject);
|
|
||||||
|
|
||||||
// Anfrage ans Backend
|
// Anfrage ans Backend
|
||||||
|
|
||||||
if (keycloak.subject != null) {
|
if (keycloak.subject) {
|
||||||
|
userStore.keycloakId = keycloak.subject;
|
||||||
//userStore.loadPtpUsersByKeycloakID(keycloak.subject);
|
//userStore.loadPtpUsersByKeycloakID(keycloak.subject);
|
||||||
userStore.getPtpUserByKeycloakID(keycloak.subject);
|
await userStore.getPtpUserByKeycloakID(keycloak.subject);
|
||||||
/*console.log(userStore.userLoaded);
|
/*console.log(userStore.userLoaded);
|
||||||
if(userStore.userLoaded) {
|
if(userStore.userLoaded) {
|
||||||
console.log("Hier ist der Bruder: " + JSON.stringify(userStore.user));
|
console.log("Hier ist der Bruder: " + JSON.stringify(userStore.user));
|
||||||
}*/
|
}*/
|
||||||
userStore.loadPtpUsersByKeycloakID(keycloak.subject).then(user => {
|
userStore.loadPtpUsersByKeycloakID(keycloak.subject).then(user => {
|
||||||
console.log(JSON.stringify(user));
|
console.log(JSON.stringify(user));
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
console.error("hier ist was schlimmes passiert menno");
|
console.error("hier ist was schlimmes passiert menno");
|
||||||
}
|
}
|
||||||
|
|
||||||
keycloakStore.setKeycloak(keycloak);
|
|
||||||
|
|||||||
@@ -1,47 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="row items-center justify-evenly">
|
<q-page class="row items-center justify-evenly">
|
||||||
<example-component
|
<q-btn v-if="!userStore.keycloak" @click="login()" label="Login" />
|
||||||
title="Example component"
|
<q-btn @click="$router.push('/test')" label="Test" />
|
||||||
active
|
|
||||||
:todos="todos"
|
|
||||||
:meta="meta"
|
|
||||||
></example-component>
|
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script lang="ts">
|
||||||
import { ref } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { Todo, Meta } from 'components/models';
|
import { useUserStore } from 'stores/user-store';
|
||||||
import ExampleComponent from 'components/ExampleComponent.vue';
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'IndexPage'
|
|
||||||
});
|
|
||||||
|
|
||||||
const todos = ref<Todo[]>([
|
export default defineComponent({
|
||||||
{
|
components: {
|
||||||
id: 1,
|
|
||||||
content: 'ct1'
|
|
||||||
},
|
},
|
||||||
{
|
setup() {
|
||||||
id: 2,
|
const userStore = useUserStore();
|
||||||
content: 'ct2'
|
const login = () => {
|
||||||
},
|
userStore.login();
|
||||||
{
|
};
|
||||||
id: 3,
|
return { login, userStore };
|
||||||
content: 'ct3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
content: 'ct4'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
content: 'ct5'
|
|
||||||
}
|
}
|
||||||
]);
|
|
||||||
|
|
||||||
const meta = ref<Meta>({
|
|
||||||
totalCount: 1200
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import ProtectedData from 'components/ProtectedData.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<h1>Hallloooooooooo</h1>
|
<h1>Hallloooooooooo</h1>
|
||||||
|
<ProtectedData />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
import { store } from 'quasar/wrappers'
|
|
||||||
import { createPinia } from 'pinia'
|
|
||||||
import { Router } from 'vue-router';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* When adding new properties to stores, you should also
|
|
||||||
* extend the `PiniaCustomProperties` interface.
|
|
||||||
* @see https://pinia.vuejs.org/core-concepts/plugins.html#typing-new-store-properties
|
|
||||||
*/
|
|
||||||
declare module 'pinia' {
|
|
||||||
export interface PiniaCustomProperties {
|
|
||||||
readonly router: Router;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If not building with SSR mode, you can
|
|
||||||
* directly export the Store instantiation;
|
|
||||||
*
|
|
||||||
* The function below can be async too; either use
|
|
||||||
* async/await or return a Promise which resolves
|
|
||||||
* with the Store instance.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export default store((/* { ssrContext } */) => {
|
|
||||||
const pinia = createPinia()
|
|
||||||
|
|
||||||
// You can add Pinia plugins here
|
|
||||||
// pinia.use(SomePiniaPlugin)
|
|
||||||
|
|
||||||
return pinia
|
|
||||||
})
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
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;
|
|
||||||
},
|
|
||||||
async logout(){
|
|
||||||
await this.keycloak?.logout();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -1,26 +1,66 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import {api} from 'boot/axios';
|
import { api } from 'src/boot/axios';
|
||||||
import {ptpUser, responseModel} from 'src/models';
|
import { ptpUser, responseModel } from 'src/models';
|
||||||
import Keycloak from 'keycloak-js';
|
import Keycloak, { KeycloakInitOptions, KeycloakLoginOptions } from 'keycloak-js';
|
||||||
|
|
||||||
export const useUserStore = defineStore('userStore', {
|
export const useUserStore = defineStore('userStore', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
user: {"keycloakID":null,"firstName":null,"lastName":null,"username":null},
|
user: null as ptpUser | null,
|
||||||
userLoaded: false,
|
userLoaded: false,
|
||||||
|
keycloak: null as Keycloak | null,
|
||||||
|
keycloakId: "",
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {},
|
||||||
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
getPtpUserByKeycloakID(keycloakID : string) {
|
async getPtpUserByKeycloakID(keycloakID : string) {
|
||||||
this.loadPtpUsersByKeycloakID(keycloakID).then((response : responseModel) => {
|
await this.loadPtpUsersByKeycloakID(keycloakID).then((response : responseModel) => {
|
||||||
this.user = response.response;
|
this.user = response.response;
|
||||||
this.userLoaded = true;
|
this.userLoaded = true;
|
||||||
console.log("ich habe das gesetzt: " + JSON.stringify(this.user) + " / " + this.userLoaded);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async loadPtpUsersByKeycloakID(keycloakID : string) : Promise<responseModel> {
|
async loadPtpUsersByKeycloakID(keycloakID : string) : Promise<responseModel> {
|
||||||
return (await api.get("/users/login/"+keycloakID)).data;
|
return (await api.get("/users/login/"+keycloakID)).data;
|
||||||
},
|
},
|
||||||
|
async initKeycloak() {
|
||||||
|
/**
|
||||||
|
* Variablen sind in quasar.config.js definiert und werden hier verwendet.
|
||||||
|
* @param keycloakPort Port, auf dem Keycloak läuft, hinterlegt in docker-compose.yml
|
||||||
|
* @param frontendPort Port, auf dem das Frontend läuft, hinterlegt in quasar.config.js und realm-export.json von Keycloak für die Redirect-URL
|
||||||
|
* @param realm Name des Realms, hinterlegt in realm-export.json von Keycloak
|
||||||
|
* @param clientId Name des Clients, hinterlegt in realm-export.json von Keycloak
|
||||||
|
*/
|
||||||
|
const keycloakPort: string = "" + process.env.PORT_KEYCLOAK;
|
||||||
|
const frontendPort: string = "" + process.env.PORT_FRONTEND;
|
||||||
|
const realm : string= "" + process.env.KEYCLOAK_REALM;
|
||||||
|
const clientId: string = "" + process.env.KEYCLOAK_CLIENT_ID;
|
||||||
|
const keycloak: Keycloak = new Keycloak({
|
||||||
|
url: 'http://localhost:' + keycloakPort + '/',
|
||||||
|
realm: realm,
|
||||||
|
clientId: clientId
|
||||||
|
});
|
||||||
|
const initOptions: KeycloakInitOptions = {
|
||||||
|
onLoad: 'login-required', //erzwingt Login
|
||||||
|
redirectUri: 'http://localhost:' + frontendPort + '/',
|
||||||
|
checkLoginIframe: false,
|
||||||
|
locale: 'login-required',
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await keycloak.init(initOptions).then( (auth: boolean): void => {
|
||||||
|
console.log("Authenticated: " + auth);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
this.keycloak = keycloak;
|
||||||
|
return keycloak;
|
||||||
|
},
|
||||||
|
async login() {
|
||||||
|
if(!this.keycloak){
|
||||||
|
await this.initKeycloak();
|
||||||
|
}else await this.keycloak?.login( {prompt: 'login'} as KeycloakLoginOptions);
|
||||||
|
},
|
||||||
|
async logout() {
|
||||||
|
window.location.href= 'http://localhost:' + process.env.PORT_KEYCLOAK + '/realms/' + process.env.KEYCLOAK_REALM + '/protocol/openid-connect/logout?post_logout_redirect_uri=http%3A%2F%2Flocalhost:' + process.env.PORT_FRONTEND + '&client_id=' + process.env.KEYCLOAK_CLIENT_ID;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,12 +3,4 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "."
|
"baseUrl": "."
|
||||||
},
|
},
|
||||||
"exclude": [
|
}
|
||||||
"./dist",
|
|
||||||
"./.quasar",
|
|
||||||
"./node_modules",
|
|
||||||
"./src-capacitor",
|
|
||||||
"./src-cordova",
|
|
||||||
"./quasar.config.*.temporary.compiled*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user