@simitgroup/simpleapp-generator 1.1.28 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/ReleaseNote.md +11 -0
- package/docs/language.md +19 -0
- package/package.json +1 -1
- package/src/framework.ts +1 -1
- package/templates/nest/src/simpleapp/generate/commons/middlewares/tenant.middleware.ts.eta +1 -1
- package/templates/nest/src/simpleapp/services/docno.service.ts.eta +1 -1
- package/templates/nuxt/app.vue.eta +1 -0
- package/templates/nuxt/components/session/SessionBlock.vue.eta +49 -0
- package/templates/nuxt/components/simpleApp/SimpleAppInput.vue.eta +2 -2
- package/templates/nuxt/composables/getOpenApi.generate.ts.eta +51 -6
- package/templates/nuxt/composables/getUserStore.generate.ts.eta +5 -2
- package/templates/nuxt/composables/logout.generate.ts.eta +8 -19
- package/templates/nuxt/middleware/30.acl.global.ts.eta +5 -5
- package/templates/nuxt/nuxt.config.ts._eta +1 -1
- package/templates/nuxt/pages/login.vue.eta +22 -19
- package/templates/nuxt/pages/relogin.vue.eta +6 -0
- package/templates/nuxt/plugins/10.simpleapp-event.ts.eta +1 -2
- package/templates/nuxt/plugins/20.simpleapp-userstore.ts.eta +24 -9
- package/templates/nuxt/server/api/auth/[...].ts.eta +53 -11
- package/templates/nuxt/server/api/auth/logout.ts.eta +4 -2
- package/templates/nuxt/types/events.ts.eta +1 -0
- package/templates/project/lang/default._json +1 -0
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@ SimpleApp generator is a typescript code generator for convert jsonschemas becom
|
|
|
33
33
|
3. [frontend walk through](./docs/frontend.md)
|
|
34
34
|
4. [End to End test](./docs/test.md)
|
|
35
35
|
5. [BPMN walk through](./docs/bpmn.md)
|
|
36
|
+
6. [Language](./doc/language.md)
|
|
36
37
|
|
|
37
38
|
# Quick start
|
|
38
39
|
1. Simpleapp implement database transaction, and require mongodb cluster, below setup 3 nodes
|
package/ReleaseNote.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
[1.2.0]
|
|
2
|
+
1. lot of house keeping
|
|
3
|
+
2. frontend more stable login using keycloak
|
|
4
|
+
3. reduce too much console log at backend
|
|
5
|
+
4. build frontend/lang/df.ts instead of directly edit
|
|
6
|
+
5. some improvement of simpleappinput, like add more probs and reduce console error
|
|
7
|
+
6. simplified generated frontend page by using centralize tool bar
|
|
8
|
+
7. support document status
|
|
9
|
+
8. give frontend freedom to edit header bar and menu bar
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
[1.1.24]
|
|
2
13
|
1. fix cannot create tenant due to fullname miss-spell
|
|
3
14
|
2. fix viewer create record auto redirect
|
package/docs/language.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
To support multiple language in simpleapp project, you shall understand basic ideal of:
|
|
4
|
+
1. i18n
|
|
5
|
+
2. file & folder structures related to languages
|
|
6
|
+
3. how to use language key in source code
|
|
7
|
+
|
|
8
|
+
# i18n
|
|
9
|
+
Simpleapp generator use @nuxt/i18n page, you can learn basic ideal from it
|
|
10
|
+
|
|
11
|
+
# file & folders
|
|
12
|
+
After project initialize correctly, everything is preconfigure as nuxt3 i18n practises. However, you shall know
|
|
13
|
+
1. you shall define all default language key/message in `project-root/lang/default.json`, it will later copy into `frontend/lang/df.ts`.
|
|
14
|
+
2. `fontend/lang/df.ts` consider as "unpolish" language file, will be override every time to frontend code regenerate, you shall maintain all language key as (1)
|
|
15
|
+
3. after project completed, developer may pass `frontend/lang/df.ts` to suitable person (or chatgpt) to create proper `en.ts`, `cn.ts`
|
|
16
|
+
4. put after translated file (`en.ts, cn.ts,...`) into `frontend/lang`
|
|
17
|
+
|
|
18
|
+
# how to use language key
|
|
19
|
+
in source code, just use syntax `t('yourkey')`, it will auto pick correct language file and language key
|
package/package.json
CHANGED
package/src/framework.ts
CHANGED
|
@@ -71,7 +71,7 @@ export const prepareNest = (callback:Function)=>{
|
|
|
71
71
|
if(!fs.existsSync(`${targetfolder}/.env`)){
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
exec(`cd ${targetfolder};pnpm install --save @nestjs/event-emitter dayjs bpmn-server@2.0.
|
|
74
|
+
exec(`cd ${targetfolder};pnpm install --save @nestjs/event-emitter dayjs bpmn-server@2.0.8-alpha2 moment @casl/ability jsonpath yaml lodash @types/lodash nest-keycloak-connect keycloak-connect bpmn-client @nestjs/serve-static jsonwebtoken axios @darkwolf/base64url json-schema @wearenova/mongoose-tenant @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats ajv-errors @nestjs/config`,async (error, stdout, stderr)=>{
|
|
75
75
|
// log.info(`dependency installed`)
|
|
76
76
|
if(!error){
|
|
77
77
|
// fs.mkdirSync(`${targetfolder}/public_html`,{recursive:true})
|
|
@@ -27,7 +27,7 @@ import { UserContext } from '../user.context';
|
|
|
27
27
|
@Injectable()
|
|
28
28
|
export class TenantMiddleware implements NestMiddleware {
|
|
29
29
|
protected defaultxorg = Base64URL.encodeText('0-0-0');
|
|
30
|
-
protected excludeXorgs = ['/profile', '/profile/tenant'];
|
|
30
|
+
protected excludeXorgs = ['/profile', '/profile/tenant','/profile/session'];
|
|
31
31
|
protected logger = new Logger();
|
|
32
32
|
protected transController;
|
|
33
33
|
constructor(
|
|
@@ -71,7 +71,7 @@ export class DocnoformatService extends DocnoformatProcessor {
|
|
|
71
71
|
undefined,
|
|
72
72
|
{default:'desc'}
|
|
73
73
|
);
|
|
74
|
-
console.log('searchresult',searchresult);
|
|
74
|
+
//console.log('searchresult',searchresult);
|
|
75
75
|
let data: any = [];
|
|
76
76
|
for (let i = 0; i < searchresult.length; i++) {
|
|
77
77
|
const s = searchresult[i];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<Dialog v-model:visible="showDialog" modal :pt="{root:{class:'w-1/3'}}"
|
|
4
|
+
:header="t('sessionExpire')">
|
|
5
|
+
<div>
|
|
6
|
+
{{ t('reloginMessage') }}
|
|
7
|
+
</div>
|
|
8
|
+
<div class="text-right">
|
|
9
|
+
<Button @click="relogin" class="btn-primary">
|
|
10
|
+
{{ t('login') }}
|
|
11
|
+
</Button>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</Dialog>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
</template>
|
|
21
|
+
<script lang="ts" setup>
|
|
22
|
+
import {PROFILEApi} from '~/simpleapp/generate/openapi'
|
|
23
|
+
const showDialog = ref(false)
|
|
24
|
+
const tabvisible = ref('')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
addEventListener("visibilitychange", async (event) => {
|
|
28
|
+
tabvisible.value = document.visibilityState
|
|
29
|
+
|
|
30
|
+
if(document.visibilityState ==='visible'){
|
|
31
|
+
//focus tab, try session still active?
|
|
32
|
+
const result = await getApiSession()
|
|
33
|
+
if(result){
|
|
34
|
+
showDialog.value=false
|
|
35
|
+
}else{
|
|
36
|
+
showDialog.value=true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const relogin= ()=>{
|
|
43
|
+
window.open(useRuntimeConfig().public.APP_URL+'/relogin')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
</script>
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
<InputText type="date" :pt="pt"
|
|
15
15
|
v-else-if="inputType == SimpleAppInputType.date"
|
|
16
16
|
:inputId="slotprops.uuid" :path="setting.instancepath"
|
|
17
|
-
v-model="
|
|
17
|
+
v-model="datevalue" @update:modelValue="updateDate" :readonly="isReadonly"
|
|
18
18
|
:placeholder="placeholder"
|
|
19
19
|
v-bind="(componentProps as InputTextProps)"/>
|
|
20
20
|
<!-- calendar component -->
|
|
21
21
|
<Calendar type="date" :pt="pt" class="flex flex-col"
|
|
22
22
|
v-else-if="SimpleAppInputType.calendar==inputType"
|
|
23
23
|
:inputId="slotprops.uuid" :path="setting.instancepath"
|
|
24
|
-
v-model="
|
|
24
|
+
v-model="datevalue" @update:modelValue="updateDate" :readonly="isReadonly"
|
|
25
25
|
:placeholder="placeholder"
|
|
26
26
|
v-bind="(componentProps as CalendarProps)"/>
|
|
27
27
|
<!-- time component -->
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This file was automatically generated by simpleapp generator during initialization.
|
|
3
3
|
* DO NOT MODIFY IT BY HAND.
|
|
4
|
-
* last change
|
|
4
|
+
* last change 2024-01-24
|
|
5
5
|
* author: Ks Tan
|
|
6
6
|
*/
|
|
7
7
|
|
|
@@ -16,7 +16,10 @@ const getAxiosConfig = () => {
|
|
|
16
16
|
};
|
|
17
17
|
return config
|
|
18
18
|
}
|
|
19
|
-
export const getApiSession = async ()=>
|
|
19
|
+
export const getApiSession = async ()=> {
|
|
20
|
+
const res = await (new o.PROFILEApi(getAxiosConfig(),undefined,useNuxtApp().$axios)).getSession()
|
|
21
|
+
return res
|
|
22
|
+
}
|
|
20
23
|
|
|
21
24
|
export const getDocumentApi = (documentName: string): any => {
|
|
22
25
|
//const { csrf } = useCsrf()
|
|
@@ -25,11 +28,53 @@ export const getDocumentApi = (documentName: string): any => {
|
|
|
25
28
|
|
|
26
29
|
const config = getAxiosConfig()
|
|
27
30
|
const docsOpenapi: any = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
'tenant': new o.TENANTApi(config),
|
|
32
|
+
|
|
33
|
+
'organization': new o.ORGApi(config),
|
|
34
|
+
|
|
35
|
+
'branch': new o.BRANCHApi(config),
|
|
36
|
+
|
|
37
|
+
'permission': new o.PERMApi(config),
|
|
38
|
+
|
|
39
|
+
'autoincreament': new o.AUTOINCApi(config),
|
|
40
|
+
|
|
41
|
+
'docnoformat': new o.DOCNOApi(config),
|
|
42
|
+
|
|
43
|
+
'category': new o.CATApi(config),
|
|
44
|
+
|
|
45
|
+
'customer': new o.CUSTApi(config),
|
|
46
|
+
|
|
47
|
+
'enrollment': new o.ENROLLApi(config),
|
|
48
|
+
|
|
49
|
+
'invoice': new o.INVApi(config),
|
|
50
|
+
|
|
51
|
+
'level': new o.LVLApi(config),
|
|
52
|
+
|
|
53
|
+
'payment': new o.PAYApi(config),
|
|
54
|
+
|
|
55
|
+
'paymentmethod': new o.PAYMETHODApi(config),
|
|
56
|
+
|
|
57
|
+
'period': new o.PERIODApi(config),
|
|
58
|
+
|
|
59
|
+
'product': new o.PRDApi(config),
|
|
60
|
+
|
|
61
|
+
'room': new o.ROOMApi(config),
|
|
62
|
+
|
|
63
|
+
'schedule': new o.SCHEDULEApi(config),
|
|
64
|
+
|
|
65
|
+
'school': new o.SCHOOLApi(config),
|
|
66
|
+
|
|
67
|
+
'student': new o.STUApi(config),
|
|
68
|
+
|
|
69
|
+
'studentgroup': new o.STUGROUPApi(config),
|
|
70
|
+
|
|
71
|
+
'teacher': new o.TEACHERApi(config),
|
|
72
|
+
|
|
73
|
+
'tuitionclass': new o.TUITIONApi(config),
|
|
74
|
+
|
|
75
|
+
'user': new o.USERApi(config),
|
|
31
76
|
|
|
32
|
-
|
|
77
|
+
|
|
33
78
|
};
|
|
34
79
|
if (!docsOpenapi[documentName]) {
|
|
35
80
|
console.error(
|
|
@@ -7,11 +7,14 @@ export const reloadUserStore = async () =>{
|
|
|
7
7
|
await $userstore.loadRemoteUserInfo()
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export const getUserProfile = () =>{
|
|
10
|
+
export const getUserProfile = () =>{
|
|
11
|
+
const userstore = getUserStore()
|
|
12
|
+
|
|
11
13
|
return getUserStore().getUserInfo()
|
|
12
14
|
}
|
|
15
|
+
|
|
13
16
|
export const getCurrentXorg = () =>{
|
|
14
|
-
return
|
|
17
|
+
return (useRoute().params.xorg) ? String(useRoute().params.xorg) : undefined
|
|
15
18
|
}
|
|
16
19
|
export const getPageBaseUrl = (resourcename:string) =>{
|
|
17
20
|
return `/${getCurrentXorg()}/${resourcename}`;
|
|
@@ -1,22 +1,11 @@
|
|
|
1
|
-
export const logout = async () => {
|
|
1
|
+
export const logout = async (redirecturl:string='') => {
|
|
2
|
+
const redirectdata = encodeURIComponent(redirecturl)
|
|
2
3
|
const { signOut } = useAuth();
|
|
3
4
|
const { data } = await <any>useFetch('/api/auth/logout');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// console.log('logoutkeycloak',data['value']['path'])
|
|
10
|
-
if(data['value']['path']){
|
|
11
|
-
navigateTo(data.value.path, { external: true })
|
|
12
|
-
}
|
|
13
|
-
//
|
|
14
|
-
}
|
|
5
|
+
// remove session
|
|
6
|
+
await signOut({redirect:false});
|
|
7
|
+
let addPath = encodeURIComponent(`/login?callbackUrl=${redirectdata}`);
|
|
8
|
+
const tourl= `${data.value.path}${addPath}`
|
|
9
|
+
navigateTo(tourl, { external: true })
|
|
15
10
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
// const addPath = encodeURIComponent("/login");
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
};
|
|
11
|
+
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This file was automatically generated by simpleapp generator. Every
|
|
3
3
|
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
4
|
-
* last change
|
|
4
|
+
* last change 2024-01-23
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
7
|
import { getUserProfile } from './../composables/getUserStore.generate';
|
|
8
8
|
import {MenuData} from '~/types'
|
|
9
9
|
export default defineNuxtRouteMiddleware((to, from) => {
|
|
10
10
|
|
|
11
|
+
// return true;
|
|
11
12
|
const userprofile = getUserProfile()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if( getPublicResource(String(to.params['xorg'])).filter((item:MenuData)=>to.fullPath === item.url)){
|
|
13
|
+
if(to.path=='/relogin'){
|
|
14
|
+
return true
|
|
15
|
+
}else if( getPublicResource(String(to.params['xorg'])).filter((item:MenuData)=>to.fullPath === item.url)){
|
|
16
16
|
return true
|
|
17
17
|
}// no permission control needed yet
|
|
18
18
|
else if(!to.params['xorg']){
|
|
@@ -1,27 +1,30 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<NuxtPage />
|
|
3
|
+
</template>
|
|
1
4
|
<script setup lang="ts">
|
|
2
5
|
/**
|
|
3
6
|
* This file was automatically generated by simpleapp generator. Every
|
|
4
7
|
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
5
|
-
* last change
|
|
8
|
+
* last change 2024-01-22
|
|
6
9
|
* Author: Ks Tan
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
definePageMeta({
|
|
13
|
+
name: 'Login',
|
|
10
14
|
auth: false,
|
|
11
|
-
})
|
|
15
|
+
})
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
const { signIn } = useAuth()
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</template>
|
|
17
|
+
const route = useRoute();
|
|
18
|
+
const { signIn } = useAuth()
|
|
19
|
+
const callbackUrl = ref('')
|
|
20
|
+
onMounted(async () => {
|
|
21
|
+
if(route.query.callbackUrl) {
|
|
22
|
+
callbackUrl.value = <string>route.query.callbackUrl;
|
|
23
|
+
}else{
|
|
24
|
+
callbackUrl.value = '/'
|
|
25
|
+
}
|
|
26
|
+
callbackUrl.value = decodeURIComponent(callbackUrl.value)
|
|
27
|
+
console.log("callbackUrlcallbackUrlcallbackUrl",callbackUrl.value)
|
|
28
|
+
await signIn('keycloak', { callbackUrl: callbackUrl.value })
|
|
29
|
+
})
|
|
30
|
+
</script>
|
|
@@ -31,8 +31,7 @@ export default defineNuxtPlugin( async(nuxtApp) => {
|
|
|
31
31
|
|
|
32
32
|
}
|
|
33
33
|
else if(error.response.status==401){
|
|
34
|
-
console.error("axios 401 session expired,
|
|
35
|
-
logout()
|
|
34
|
+
console.error("axios 401 session expired, pop up for relogin")
|
|
36
35
|
}else if(error.response && error.response.status){
|
|
37
36
|
console.error("have error response")
|
|
38
37
|
createError({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This file was automatically generated by simpleapp generator. Every
|
|
3
3
|
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
4
|
-
* last change
|
|
4
|
+
* last change 2024-01-23
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
7
|
import { defineNuxtPlugin } from "#app";
|
|
@@ -11,8 +11,7 @@ import _ from 'lodash'
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
export default defineNuxtPlugin( async(nuxtApp) => {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
console.log("start plugin 20")
|
|
16
15
|
const useUserStore = defineStore('userstore', {
|
|
17
16
|
state: ()=>({
|
|
18
17
|
_id: ref(''),
|
|
@@ -91,10 +90,21 @@ export default defineNuxtPlugin( async(nuxtApp) => {
|
|
|
91
90
|
return Promise.reject(errdata)
|
|
92
91
|
}
|
|
93
92
|
})
|
|
94
|
-
},
|
|
93
|
+
},
|
|
95
94
|
getCurrentXorg(){
|
|
96
95
|
return (useRoute().params.xorg) ? String(useRoute().params.xorg) : undefined
|
|
97
96
|
},
|
|
97
|
+
async pingSession(){
|
|
98
|
+
let xorg = this.getCurrentXorg()
|
|
99
|
+
let apiurl=''
|
|
100
|
+
if(xorg===undefined){
|
|
101
|
+
apiurl = `${useRuntimeConfig().public.APP_URL}/api`
|
|
102
|
+
}else{
|
|
103
|
+
apiurl = `${useRuntimeConfig().public.APP_URL}/api/${xorg}`
|
|
104
|
+
}
|
|
105
|
+
const {$axios} = useNuxtApp()
|
|
106
|
+
return await new PROFILEApi(undefined,apiurl,$axios).getSession()
|
|
107
|
+
},
|
|
98
108
|
async decideInvitation(id:string,decision:string){
|
|
99
109
|
const apiurl = `${useRuntimeConfig().public.APP_URL}/api`
|
|
100
110
|
const {$axios} = useNuxtApp()
|
|
@@ -170,12 +180,17 @@ export default defineNuxtPlugin( async(nuxtApp) => {
|
|
|
170
180
|
}
|
|
171
181
|
}
|
|
172
182
|
})
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if(
|
|
183
|
+
console.log("after define user store")
|
|
184
|
+
|
|
185
|
+
if( useRoute().meta.auth !==false){
|
|
186
|
+
if(await useUserStore().pingSession()){
|
|
187
|
+
console.log("ping session ok")
|
|
177
188
|
await useUserStore().loadRemoteUserInfo()
|
|
178
|
-
}
|
|
189
|
+
}else{
|
|
190
|
+
console.log("No login session", useRoute().path)
|
|
191
|
+
await logout(useRoute().path)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
179
194
|
|
|
180
195
|
return {
|
|
181
196
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This file was automatically generated by simpleapp generator. Every
|
|
3
3
|
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
4
|
-
* last change
|
|
4
|
+
* last change 2024-01-24
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
7
|
import { NuxtAuthHandler } from "#auth";
|
|
8
8
|
import KeycloakProvider from "next-auth/providers/keycloak";
|
|
9
|
-
|
|
9
|
+
// import GithubProvider from "next-auth/providers/github";
|
|
10
10
|
|
|
11
11
|
export default NuxtAuthHandler({
|
|
12
12
|
secret: process.env.AUTH_SECRET_KEY,
|
|
@@ -14,7 +14,10 @@ export default NuxtAuthHandler({
|
|
|
14
14
|
maxAge: 60 * 60 * 24 * 30,
|
|
15
15
|
},
|
|
16
16
|
providers: [
|
|
17
|
-
|
|
17
|
+
// GithubProvider.default({
|
|
18
|
+
// clientId: process.env.GITHUB_ID ?? '',
|
|
19
|
+
// clientSecret: process.env.GITHUB_SECRET ?? '',
|
|
20
|
+
// }),
|
|
18
21
|
// @ts-expect-error
|
|
19
22
|
KeycloakProvider.default({
|
|
20
23
|
clientId: process.env.OAUTH2_CLIENTID ?? "",
|
|
@@ -28,7 +31,7 @@ export default NuxtAuthHandler({
|
|
|
28
31
|
token: `${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/token`,
|
|
29
32
|
logout:
|
|
30
33
|
`${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/logout?redirect_uri=` +
|
|
31
|
-
encodeURIComponent(String(process.env.
|
|
34
|
+
encodeURIComponent(String(process.env.NUXT_PUBLIC_API_BASE)),
|
|
32
35
|
},
|
|
33
36
|
// accessTokenUrl: `${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/token`,
|
|
34
37
|
// requestTokenUrl: `${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/token`,
|
|
@@ -49,8 +52,8 @@ export default NuxtAuthHandler({
|
|
|
49
52
|
codeChallengeMethod: "S256",
|
|
50
53
|
redirect: {
|
|
51
54
|
logout: "/",
|
|
52
|
-
callback: "/",
|
|
53
|
-
home: "/",
|
|
55
|
+
// callback: "/",
|
|
56
|
+
// home: "/",
|
|
54
57
|
},
|
|
55
58
|
}),
|
|
56
59
|
],
|
|
@@ -58,17 +61,56 @@ export default NuxtAuthHandler({
|
|
|
58
61
|
signIn: "/login",
|
|
59
62
|
},
|
|
60
63
|
callbacks: {
|
|
64
|
+
// async redirect({ url, baseUrl }) {
|
|
65
|
+
|
|
66
|
+
// console.log(url, baseUrl)
|
|
67
|
+
// return baseUrl
|
|
68
|
+
// },
|
|
61
69
|
async jwt({ token, account }) {
|
|
70
|
+
// Persist the OAuth access_token to the token right after signin
|
|
62
71
|
if (account) {
|
|
63
72
|
token.accessToken = account.access_token;
|
|
73
|
+
token.refreshToken = account.refresh_token;
|
|
74
|
+
token.expiresAt = account.expires_at;
|
|
75
|
+
} else if (Date.now() < (<number>token.expiresAt) * 1000) {
|
|
76
|
+
return token;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// try refresh token
|
|
80
|
+
const response = await fetch(`${process.env.OAUTH2_CONFIGURL}/protocol/openid-connect/token`, {
|
|
81
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
82
|
+
body: new URLSearchParams({
|
|
83
|
+
client_id: process.env.OAUTH2_CLIENTID ?? "",
|
|
84
|
+
client_secret: process.env.OAUTH2_CLIENTSECRET ?? "",
|
|
85
|
+
grant_type: "refresh_token",
|
|
86
|
+
refresh_token: <string>token.refreshToken ?? "",
|
|
87
|
+
}),
|
|
88
|
+
method: "POST",
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const newToken = await response.json();
|
|
92
|
+
|
|
93
|
+
if(!response.ok) {
|
|
94
|
+
/** @todo handle refresh token failed */
|
|
95
|
+
return token
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
...token,
|
|
100
|
+
accessToken: newToken.access_token,
|
|
101
|
+
// record next access token expires time
|
|
102
|
+
expiresAt: Math.floor(Date.now() / 1000 + newToken.expires_in),
|
|
103
|
+
// Fall back to old refresh token, but note that
|
|
104
|
+
// many providers may only allow using a refresh token once.
|
|
105
|
+
refreshToken: newToken.refresh_token ?? token.refresh_token,
|
|
64
106
|
}
|
|
65
|
-
return token;
|
|
66
107
|
},
|
|
67
|
-
async session({ session
|
|
68
|
-
|
|
108
|
+
async session({ session, token, user }) {
|
|
109
|
+
// console.log("session", session);
|
|
110
|
+
// Send properties to the client, like an access_token from a provider.
|
|
111
|
+
const sessiondata:any = {...session}
|
|
69
112
|
sessiondata.accessToken = <string>token.accessToken;
|
|
70
113
|
return sessiondata;
|
|
71
114
|
},
|
|
72
|
-
|
|
73
115
|
},
|
|
74
|
-
});
|
|
116
|
+
});
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* This file was automatically generated by simpleapp generator. Every
|
|
3
3
|
* MODIFICATION OVERRIDE BY GENERATEOR
|
|
4
|
-
* last change
|
|
4
|
+
* last change 2024-01-24
|
|
5
5
|
* Author: Ks Tan
|
|
6
6
|
*/
|
|
7
7
|
export default defineEventHandler(async (event) => {
|
|
8
8
|
const path = `${
|
|
9
9
|
process.env.OAUTH2_CONFIGURL
|
|
10
|
-
}/protocol/openid-connect/logout?redirect_uri=${encodeURIComponent(
|
|
10
|
+
}/protocol/openid-connect/logout?redirect_uri=${encodeURIComponent(
|
|
11
|
+
process.env.AUTH_ORIGIN ?? ""
|
|
12
|
+
)}`;
|
|
11
13
|
|
|
12
14
|
return {
|
|
13
15
|
path: path
|