@gandalan/weblibs 0.0.41 → 1.0.1
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 +9 -8
- package/api/IDAS.js +83 -70
- package/api/RESTClient.js +79 -2
- package/index.js +2 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -4,27 +4,28 @@ WebLibs for Gandalan JS/TS/Svelte projects
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
```js
|
|
7
|
-
import {
|
|
8
|
-
let idas =
|
|
9
|
-
|
|
10
|
-
// bei Bedarf wird der Client zur Anmeldung umgeleitet, danach wird die aktuelle Seite wieder aufgerufen
|
|
11
|
-
idas.authenticateWithSSO();
|
|
7
|
+
import { IDASFactory } from '@gandalan/weblibs';
|
|
8
|
+
let idas = IDASFactory.create();
|
|
12
9
|
```
|
|
13
10
|
|
|
11
|
+
IDAS ab Version 1.0.0 verwendet JWT-Token für die Authentifizierung mit WebAPI.
|
|
12
|
+
|
|
14
13
|
Danach z.B. Zugriff auf die Mandant-Guid:
|
|
15
14
|
|
|
16
15
|
```js
|
|
17
|
-
let mandantGuid = idas.mandantGuid;
|
|
16
|
+
let mandantGuid = await idas.then(i => i.mandantGuid);
|
|
18
17
|
```
|
|
19
18
|
|
|
20
19
|
Datenzugriffe erfolgen über die Objekte innerhalb der IDAS-Klasse
|
|
21
20
|
|
|
22
21
|
```js
|
|
23
22
|
let loader = Promise.all([
|
|
24
|
-
idas.
|
|
23
|
+
idas.
|
|
24
|
+
.then(i => i.mandanten.getAll())
|
|
25
25
|
.then(d => mandanten = d.sort((a,b) => a.Name.localeCompare(b.Name)))
|
|
26
26
|
.catch(e => error = e),
|
|
27
|
-
idas
|
|
27
|
+
idas
|
|
28
|
+
.then(i => i.rollen.getAll())
|
|
28
29
|
.then(d => rollen = d.sort((a,b) => a.Name.localeCompare(b.Name)))
|
|
29
30
|
.catch(e => error = e)
|
|
30
31
|
])
|
package/api/IDAS.js
CHANGED
|
@@ -2,142 +2,155 @@ import { RESTClient } from './RESTClient';
|
|
|
2
2
|
|
|
3
3
|
let appToken = localStorage.getItem('IDAS_AppToken') || '66B70E0B-F7C4-4829-B12A-18AD309E3970';
|
|
4
4
|
let authToken = localStorage.getItem('IDAS_AuthToken');
|
|
5
|
-
let authJwtToken = localStorage.getItem('IDAS_AuthJwtToken');
|
|
6
5
|
let apiBaseUrl = localStorage.getItem('IDAS_ApiBaseUrl') || 'https://api.dev.idas-cloudservices.net/api/';
|
|
7
|
-
|
|
8
|
-
let
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
localStorage.setItem('IDAS_AuthToken', authToken);
|
|
24
|
-
restClient = new RESTClient(apiBaseUrl, authToken);
|
|
6
|
+
let authJwtCallbackPath = localStorage.getItem('IDAS_AuthJwtCallbackPath') || '';
|
|
7
|
+
let authJwtToken;
|
|
8
|
+
|
|
9
|
+
export let IDASFactory = {
|
|
10
|
+
async create() {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
let idas = new IDAS();
|
|
13
|
+
resolve(idas.authenticateWithJwt(authJwtCallbackPath));
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
authorize() {
|
|
18
|
+
var urlParams = new URLSearchParams(location.search);
|
|
19
|
+
if (urlParams.has('t')) {
|
|
20
|
+
let idas = new IDAS();
|
|
21
|
+
idas.authorizeWithJwt(urlParams.get('t'));
|
|
25
22
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
if (urlParams.has("m")) {
|
|
24
|
+
localStorage.setItem("IDAS_MandantGuid", urlParams.get("m"));
|
|
25
|
+
}
|
|
26
|
+
if (urlParams.has("a")) {
|
|
27
|
+
localStorage.setItem("IDAS_ApiBaseUrl", urlParams.get("a"));
|
|
28
|
+
}
|
|
29
|
+
window.location.search = "";
|
|
32
30
|
}
|
|
31
|
+
}
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
const url = new URL(apiBaseUrl);
|
|
38
|
-
url.pathname = "/SSO";
|
|
39
|
-
url.search = "?a=" + appToken;
|
|
40
|
-
if (forceRenew)
|
|
41
|
-
url.search = url.search + "&forceRenew=true";
|
|
42
|
-
url.search = url.search + "&r=%target%%3Ft=%token%%26m=%mandant%";
|
|
43
|
-
let ssoAuthUrl = url.toString();
|
|
33
|
+
class IDAS {
|
|
34
|
+
restClient = undefined;
|
|
44
35
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
36
|
+
authorizeWithJwt(jwtToken, mandant = '') {
|
|
37
|
+
authJwtToken = jwtToken;
|
|
38
|
+
mandant && localStorage.setItem('IDAS_MandantGuid', mandant);
|
|
39
|
+
this.restClient = new RESTClient(apiBaseUrl, jwtToken, true);
|
|
48
40
|
}
|
|
49
41
|
|
|
50
42
|
async authenticateWithJwt(authPath) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
return new Promise(async (resolve, reject) => {
|
|
44
|
+
// no valid JWT, but try to use "refresh token" first to retrive new JWT
|
|
45
|
+
var refreshClient = new RESTClient(apiBaseUrl, '');
|
|
46
|
+
await refreshClient.checkRefreshToken(authJwtToken, () => {
|
|
47
|
+
authJwtToken = undefined;
|
|
48
|
+
// ... so repeat authenticate (should lead to /Session login page)
|
|
49
|
+
new IDAS().authenticateWithJwt(authPath);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// still not valid JWT -> authenticate
|
|
53
|
+
if (!refreshClient.token) {
|
|
54
|
+
localStorage.setItem('IDAS_AuthJwtCallbackPath', authPath);
|
|
55
|
+
const authEndpoint = (new URL(window.location.href).origin) + authPath;
|
|
56
|
+
let authUrlCallback = `${authEndpoint}?r=%target%&t=%jwt%&m=%mandant%`;
|
|
57
|
+
authUrlCallback = authUrlCallback.replace('%target%', encodeURIComponent(window.location.href));
|
|
58
|
+
|
|
59
|
+
const url = new URL(apiBaseUrl);
|
|
60
|
+
url.pathname = "/Session";
|
|
61
|
+
url.search = `?a=${appToken}&r=${encodeURIComponent(authUrlCallback)}`;
|
|
62
|
+
let jwtUrl = url.toString();
|
|
63
|
+
|
|
64
|
+
window.location = jwtUrl;
|
|
65
|
+
reject('not authenticated yet');
|
|
66
|
+
} else {
|
|
67
|
+
this.authorizeWithJwt(refreshClient.token);
|
|
68
|
+
resolve(this);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
mandantGuid = localStorage.getItem('IDAS_MandantGuid');
|
|
68
74
|
|
|
69
75
|
auth = {
|
|
76
|
+
_self: this,
|
|
70
77
|
async getCurrentAuthToken() {
|
|
71
|
-
return await restClient.put('/Login/Update/', { Token: authToken })
|
|
78
|
+
return await this._self.restClient.put('/Login/Update/', { Token: authToken })
|
|
72
79
|
},
|
|
73
80
|
};
|
|
74
81
|
|
|
75
82
|
mandanten = {
|
|
83
|
+
_self: this,
|
|
76
84
|
async getAll() {
|
|
77
|
-
return await restClient.get('/Mandanten');
|
|
85
|
+
return await this._self.restClient.get('/Mandanten');
|
|
78
86
|
},
|
|
79
87
|
async get(guid) {
|
|
80
|
-
return await restClient.get(`/Mandanten/${guid}`);
|
|
88
|
+
return await this._self.restClient.get(`/Mandanten/${guid}`);
|
|
81
89
|
},
|
|
82
90
|
async save(m) {
|
|
83
|
-
await restClient.put('/Mandanten', m);
|
|
91
|
+
await this._self.restClient.put('/Mandanten', m);
|
|
84
92
|
},
|
|
85
93
|
};
|
|
86
94
|
|
|
87
95
|
benutzer = {
|
|
96
|
+
_self: this,
|
|
88
97
|
async getAll(mandantGuid) {
|
|
89
|
-
return await restClient.get(`/BenutzerListe/${mandantGuid }/?mitRollenUndRechten=true`);
|
|
98
|
+
return await this._self.restClient.get(`/BenutzerListe/${mandantGuid }/?mitRollenUndRechten=true`);
|
|
90
99
|
},
|
|
91
100
|
async get(guid) {
|
|
92
|
-
return await restClient.get(`/Benutzer/${guid}`);
|
|
101
|
+
return await this._self.restClient.get(`/Benutzer/${guid}`);
|
|
93
102
|
},
|
|
94
103
|
async save(m) {
|
|
95
|
-
await restClient.put('/Benutzer', m);
|
|
104
|
+
await this._self.restClient.put('/Benutzer', m);
|
|
96
105
|
},
|
|
97
106
|
};
|
|
98
107
|
|
|
99
108
|
feedback = {
|
|
109
|
+
_self: this,
|
|
100
110
|
async getAll() {
|
|
101
|
-
return await restClient.get('/Feedback/');
|
|
111
|
+
return await this._self.restClient.get('/Feedback/');
|
|
102
112
|
},
|
|
103
113
|
async get(guid) {
|
|
104
|
-
return await restClient.get(`/Feedback/${guid}`);
|
|
114
|
+
return await this._self.restClient.get(`/Feedback/${guid}`);
|
|
105
115
|
},
|
|
106
116
|
async save(m) {
|
|
107
|
-
await restClient.put('/Feedback', m);
|
|
117
|
+
await this._self.restClient.put('/Feedback', m);
|
|
108
118
|
},
|
|
109
119
|
async comment(guid, commentData) {
|
|
110
|
-
await restClient.put(`/FeedbackKommentar/${guid}`, commentData);
|
|
120
|
+
await this._self.restClient.put(`/FeedbackKommentar/${guid}`, commentData);
|
|
111
121
|
},
|
|
112
122
|
async attachFile(guid, filename, data) {
|
|
113
|
-
await restClient.put(`/FeedbackAttachment/?feedbackGuid=${guid}&filename=${filename}`, data);
|
|
123
|
+
await this._self.restClient.put(`/FeedbackAttachment/?feedbackGuid=${guid}&filename=${filename}`, data);
|
|
114
124
|
},
|
|
115
125
|
async deleteFile(guid) {
|
|
116
|
-
await restClient.delete(`/FeedbackAttachment/${guid}`);
|
|
126
|
+
await this._self.restClient.delete(`/FeedbackAttachment/${guid}`);
|
|
117
127
|
},
|
|
118
128
|
};
|
|
119
129
|
|
|
120
130
|
rollen = {
|
|
131
|
+
_self: this,
|
|
121
132
|
async getAll() {
|
|
122
|
-
return await restClient.get('/Rollen');
|
|
133
|
+
return await this._self.restClient.get('/Rollen');
|
|
123
134
|
},
|
|
124
135
|
async save(m) {
|
|
125
|
-
await restClient.put('/Rollen', m);
|
|
136
|
+
await this._self.restClient.put('/Rollen', m);
|
|
126
137
|
},
|
|
127
138
|
};
|
|
128
139
|
|
|
129
140
|
vorgaenge = {
|
|
141
|
+
_self: this,
|
|
130
142
|
async getByVorgangsnummer(vorgangsNummer, jahr) {
|
|
131
|
-
return await restClient.get(`/Vorgang/${vorgangsNummer}/${jahr}`);
|
|
143
|
+
return await this._self.restClient.get(`/Vorgang/${vorgangsNummer}/${jahr}`);
|
|
132
144
|
},
|
|
133
145
|
};
|
|
134
146
|
|
|
135
147
|
positionen = {
|
|
148
|
+
_self: this,
|
|
136
149
|
async getByPcode(pcode) {
|
|
137
|
-
return await restClient.get(`/BelegPositionen/GetByPcode/${pcode}`);
|
|
150
|
+
return await this._self.restClient.get(`/BelegPositionen/GetByPcode/${pcode}`);
|
|
138
151
|
},
|
|
139
152
|
async get(guid) {
|
|
140
|
-
return await restClient.get(`/BelegPositionen/Get/${guid}`);
|
|
153
|
+
return await this._self.restClient.get(`/BelegPositionen/Get/${guid}`);
|
|
141
154
|
},
|
|
142
155
|
};
|
|
143
156
|
}
|
package/api/RESTClient.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
+
import jwt_decode from 'jwt-decode';
|
|
2
3
|
|
|
3
4
|
/*export let AppToken = "66B70E0B-F7C4-4829-B12A-18AD309E3970";
|
|
4
5
|
export let AuthToken = localStorage.getItem("AuthToken");
|
|
@@ -7,6 +8,8 @@ export let ApiBaseUrl = localStorage.getItem("ApiBaseUrl") || "https://api.dev.i
|
|
|
7
8
|
export let SiteBaseUrl = window.location.origin;
|
|
8
9
|
export let SSOAuthUrl = ApiBaseUrl.replace("/api", '') + "/SSO?a=" + AppToken + "&r=%target%?t=%token%%26m=%mandant%";*/
|
|
9
10
|
|
|
11
|
+
let authJwtRefreshToken = localStorage.getItem('IDAS_AuthJwtRefreshToken');
|
|
12
|
+
|
|
10
13
|
export class RESTClient {
|
|
11
14
|
lastError = '';
|
|
12
15
|
token = '';
|
|
@@ -22,11 +25,85 @@ export class RESTClient {
|
|
|
22
25
|
axios.defaults.headers.common['X-Gdl-AuthToken'] = this.token;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
if (this.token && isJWT) {
|
|
29
|
+
this.updateJwtToken(token);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
axios.interceptors.request.use(async (config) => {
|
|
33
|
+
await this.checkAuthorizationHeader(config);
|
|
34
|
+
return config;
|
|
27
35
|
});
|
|
28
36
|
}
|
|
29
37
|
|
|
38
|
+
async checkAuthorizationHeader(config) {
|
|
39
|
+
let authHeader = config.headers['Authorization'];
|
|
40
|
+
if (authHeader && authHeader.toString().startsWith('Bearer ')) {
|
|
41
|
+
let parts = authHeader.toString().split(' ');
|
|
42
|
+
let jwt = parts[1];
|
|
43
|
+
if (!this.isJwtTokenExpired(jwt)) {
|
|
44
|
+
// JWT token is not expired
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// expired token - refresh
|
|
49
|
+
await this.checkRefreshToken(jwt);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async checkRefreshToken(jwt, authCallback) {
|
|
54
|
+
if (!jwt && authJwtRefreshToken) {
|
|
55
|
+
this.onError = (error, message) => {
|
|
56
|
+
// LoginJwt/Refresh failed, which means "refresh token" is expired/invalid...
|
|
57
|
+
if (message.indexOf("401") != -1 || message.indexOf("403") != -1) {
|
|
58
|
+
authJwtRefreshToken = undefined;
|
|
59
|
+
localStorage.removeItem('IDAS_AuthJwtRefreshToken');
|
|
60
|
+
// ... so repeat authenticate
|
|
61
|
+
authCallback && authCallback();
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
// fetch fresh JWT
|
|
65
|
+
await this.refreshToken();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.token = jwt;
|
|
69
|
+
this.isJWT = true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
isJwtTokenExpired(jwt) {
|
|
73
|
+
if (!jwt) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let decoded = jwt_decode(jwt);
|
|
78
|
+
const utcNow = Date.parse(new Date().toUTCString()) / 1000;
|
|
79
|
+
|
|
80
|
+
if (decoded && decoded.exp >= utcNow) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
updateJwtToken(jwt) {
|
|
88
|
+
let decoded = jwt_decode(jwt);
|
|
89
|
+
let refreshToken = decoded['refreshToken'];
|
|
90
|
+
localStorage.setItem('IDAS_AuthJwtRefreshToken', refreshToken);
|
|
91
|
+
authJwtRefreshToken = refreshToken;
|
|
92
|
+
this.token = jwt;
|
|
93
|
+
this.isJWT = true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async refreshToken() {
|
|
97
|
+
try {
|
|
98
|
+
await axios.put(this.baseurl + '/LoginJwt/Refresh', { token: localStorage.getItem('IDAS_AuthJwtRefreshToken') })
|
|
99
|
+
.then(resp => {
|
|
100
|
+
this.updateJwtToken(resp.data);
|
|
101
|
+
});
|
|
102
|
+
} catch (error) {
|
|
103
|
+
this.handleError(error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
30
107
|
updateToken(token) {
|
|
31
108
|
this.token = token;
|
|
32
109
|
}
|
package/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export {
|
|
|
12
12
|
AddButton, RemoveButton, SaveButton,
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { IDASFactory } from './api/IDAS';
|
|
16
16
|
import { RESTClient } from './api/RESTClient';
|
|
17
17
|
|
|
18
|
-
export {
|
|
18
|
+
export { IDASFactory, RESTClient };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gandalan/weblibs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "WebLibs for Gandalan JS/TS/Svelte projects",
|
|
5
5
|
"author": "Philipp Reif",
|
|
6
6
|
"license": "ISC",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@mdi/js": "^7.0.96",
|
|
25
25
|
"axios": "^0.27.2",
|
|
26
|
+
"jwt-decode": "^3.1.2",
|
|
26
27
|
"svelte-table": "^0.5.1"
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|