samanbayaka 0.0.14 → 0.0.16
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 +22 -17
- package/commit-hash.mjs +1 -1
- package/helper/file/esm-loading.mjs +1 -1
- package/helper/utility/access-token-validator.mjs +171 -0
- package/index.mjs +1 -4
- package/package.json +3 -1
- package/public/signin.html +93 -0
- package/services/about/index.mjs +11 -1
- package/services/bff/index.mjs +37 -0
- package/services/gateway/index.mjs +32 -4
- package/services/kafka/index.mjs +1 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Once the package is installed, you can import the library using import or requir
|
|
|
35
35
|
import sbk from "samanbayaka"
|
|
36
36
|
```
|
|
37
37
|
# Prerequisites
|
|
38
|
-
It is assumed that NATS, Redpanda, and
|
|
38
|
+
It is assumed that NATS, Redpanda, Redis, and Etcd are installed and properly configured. All services should be discoverable through the /etc/hosts file.
|
|
39
39
|
#### Minimum required Node.js version: >= 22.x.x
|
|
40
40
|
```bash
|
|
41
41
|
node -v
|
|
@@ -46,7 +46,8 @@ Additionally, OpenObserve is used to view logs and telemetry.
|
|
|
46
46
|
#### Environment variables
|
|
47
47
|
To configure all required environment variables, create a Bash file:
|
|
48
48
|
```bash
|
|
49
|
-
|
|
49
|
+
source /etc/profile.d/sbk.sh
|
|
50
|
+
|
|
50
51
|
```
|
|
51
52
|
Paste this:
|
|
52
53
|
```bash
|
|
@@ -250,12 +251,12 @@ The Gateway is a critical service that exposes all endpoints as REST APIs. At le
|
|
|
250
251
|
```bash
|
|
251
252
|
mkdir gateway
|
|
252
253
|
cd gateway
|
|
253
|
-
|
|
254
|
+
pnpm init
|
|
254
255
|
pnpm install samanbayaka
|
|
255
256
|
touch index.mjs
|
|
256
257
|
```
|
|
257
258
|
|
|
258
|
-
Open index.mjs and paste the following:
|
|
259
|
+
Open `index.mjs` and paste the following:
|
|
259
260
|
```bash
|
|
260
261
|
import sbk from "samanbayaka"
|
|
261
262
|
await sbk.loadGatewayService()
|
|
@@ -265,7 +266,7 @@ await sbk.loadGatewayService()
|
|
|
265
266
|
```bash
|
|
266
267
|
mkdir <your_service_name>
|
|
267
268
|
cd <your_service_name>
|
|
268
|
-
|
|
269
|
+
pnpm init
|
|
269
270
|
pnpm install samanbayaka
|
|
270
271
|
touch index.mjs
|
|
271
272
|
```
|
|
@@ -274,12 +275,12 @@ A feature service, such as `hello`, can be created as follows:
|
|
|
274
275
|
```bash
|
|
275
276
|
mkdir hello
|
|
276
277
|
cd hello
|
|
277
|
-
|
|
278
|
+
pnpm init
|
|
278
279
|
pnpm install samanbayaka
|
|
279
280
|
touch index.mjs
|
|
280
281
|
```
|
|
281
282
|
|
|
282
|
-
Open index.mjs and paste the following:
|
|
283
|
+
Open `index.mjs` and paste the following:
|
|
283
284
|
```bash
|
|
284
285
|
import sbk from "samanbayaka"
|
|
285
286
|
await sbk.loadFeatureService({
|
|
@@ -325,7 +326,7 @@ await sbk.loadFeatureService({
|
|
|
325
326
|
```bash
|
|
326
327
|
mkdir <your_service_name>-<type>-<topic>
|
|
327
328
|
cd <your_service_name>-<type>-<topic>
|
|
328
|
-
|
|
329
|
+
pnpm init
|
|
329
330
|
pnpm install samanbayaka
|
|
330
331
|
touch index.mjs
|
|
331
332
|
```
|
|
@@ -333,12 +334,12 @@ An auxiliary service, such as a `producer` that publishes messages to the `STUDE
|
|
|
333
334
|
```js
|
|
334
335
|
mkdir producer-kafka-student
|
|
335
336
|
cd producer-kafka-student
|
|
336
|
-
|
|
337
|
+
pnpm init
|
|
337
338
|
pnpm install samanbayaka
|
|
338
339
|
touch index.mjs
|
|
339
340
|
```
|
|
340
341
|
|
|
341
|
-
Open index.mjs and paste the following:
|
|
342
|
+
Open `index.mjs` and paste the following:
|
|
342
343
|
```bash
|
|
343
344
|
import sbk from "samanbayaka"
|
|
344
345
|
await sbk.auxBrokerService(
|
|
@@ -365,19 +366,19 @@ rest: false
|
|
|
365
366
|
```bash
|
|
366
367
|
mkdir <your_service_name>-<type>-<topic>-<group>
|
|
367
368
|
cd <your_service_name>-<type>-<topic>-<group>
|
|
368
|
-
|
|
369
|
+
pnpm init
|
|
369
370
|
pnpm install samanbayaka
|
|
370
371
|
touch index.mjs
|
|
371
372
|
```
|
|
372
373
|
An auxiliary service, such as a `consumer` that subscribe messages from the `STUDENT` topic having group name `junior`, can be created as follows:
|
|
373
374
|
```js
|
|
374
|
-
mkdir
|
|
375
|
-
cd
|
|
376
|
-
|
|
375
|
+
mkdir consumer-kafka-student-junior
|
|
376
|
+
cd consumer-kafka-student-junior
|
|
377
|
+
pnpm init
|
|
377
378
|
pnpm install samanbayaka
|
|
378
379
|
touch index.mjs
|
|
379
380
|
```
|
|
380
|
-
Open index.mjs and paste the following:
|
|
381
|
+
Open `index.mjs` and paste the following:
|
|
381
382
|
```bash
|
|
382
383
|
import sbk from "samanbayaka"
|
|
383
384
|
await sbk.auxBrokerService(
|
|
@@ -421,11 +422,11 @@ You can also run the demo service to better understand how microservices work in
|
|
|
421
422
|
```bash
|
|
422
423
|
mkdir demo
|
|
423
424
|
cd demo
|
|
424
|
-
|
|
425
|
+
pnpm init
|
|
425
426
|
pnpm install samanbayaka
|
|
426
427
|
touch demo.mjs
|
|
427
428
|
```
|
|
428
|
-
Open and edit the demo.mjs file as follows
|
|
429
|
+
Open and edit the `demo.mjs` file as follows
|
|
429
430
|
```bash
|
|
430
431
|
import sbk from "samanbayaka"
|
|
431
432
|
await sbk.loadDemo()
|
|
@@ -435,6 +436,10 @@ Run the service, demo
|
|
|
435
436
|
node demo.mjs
|
|
436
437
|
```
|
|
437
438
|
|
|
439
|
+
## Documentation
|
|
440
|
+
|
|
441
|
+
- [docker](docs/dockers.md)
|
|
442
|
+
|
|
438
443
|
<p align="center" style="margin-top: 100px;">
|
|
439
444
|
<img src="https://moleculer.services/images/banner.png" alt="Moleculer Logo" width="600">
|
|
440
445
|
</p>
|
package/commit-hash.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const COMMIT_HASH = '
|
|
1
|
+
export const COMMIT_HASH = '6442e51';
|
|
@@ -24,7 +24,7 @@ const CONFIG_PATH = process.env.SBK_CONFIG_PATH // Environment variable of conf
|
|
|
24
24
|
/**
|
|
25
25
|
* Project absolute path
|
|
26
26
|
*/
|
|
27
|
-
const ABSOLUTE_PATH = path.join(__filename.split('samanbayaka')[0], "samanbayaka")
|
|
27
|
+
const ABSOLUTE_PATH = path.join(__filename.split('/samanbayaka/')[0], "samanbayaka")
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import ApiGateway from "moleculer-web"
|
|
2
|
+
import jwt from "jsonwebtoken"
|
|
3
|
+
import jwksClient from "jwks-rsa"
|
|
4
|
+
|
|
5
|
+
const OPENID_CONFIG = {
|
|
6
|
+
url: "https://accounts.google.com/.well-known/openid-configuration",
|
|
7
|
+
clientId: "184045176764-ugg28aegdro383pintufun14uubtt374.apps.googleusercontent.com",
|
|
8
|
+
jwksClient: {
|
|
9
|
+
cache: true,
|
|
10
|
+
cacheMaxEntries: 5,
|
|
11
|
+
cacheMaxAge: 10 * 60 * 1000,
|
|
12
|
+
rateLimit: true,
|
|
13
|
+
jwksRequestsPerMinute: 10,
|
|
14
|
+
},
|
|
15
|
+
jwtVerifyAlgo: ["RS256"],
|
|
16
|
+
client: {},
|
|
17
|
+
issuer: "",
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// let client
|
|
21
|
+
// let issuer
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Retrieves the public signing key corresponding to a JWT `kid`.
|
|
25
|
+
*
|
|
26
|
+
* Used by JWT verification libraries (such as `jsonwebtoken`)
|
|
27
|
+
* to dynamically resolve signing keys from a JWKS endpoint.
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} header - Decoded JWT header.
|
|
30
|
+
* @param {string} header.kid - Key ID used to identify the signing key.
|
|
31
|
+
* @param {Function} callback - Callback function invoked after key retrieval.
|
|
32
|
+
* @param {Error|null} callback.err - Error object if key retrieval fails.
|
|
33
|
+
* @param {string|null} callback.key - PEM formatted public key.
|
|
34
|
+
*
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
37
|
+
const getKey = (header, callback) => {
|
|
38
|
+
|
|
39
|
+
OPENID_CONFIG.client.getSigningKey(
|
|
40
|
+
header.kid,
|
|
41
|
+
(err, key) => {
|
|
42
|
+
|
|
43
|
+
if (err) {
|
|
44
|
+
callback(err)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
callback(
|
|
49
|
+
null,
|
|
50
|
+
key.publicKey || key.rsaPublicKey
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Initializes OpenID Connect configuration and JWKS client.
|
|
60
|
+
*
|
|
61
|
+
* Fetches the OpenID configuration document from the configured
|
|
62
|
+
* issuer endpoint and creates a cached JWKS client for JWT
|
|
63
|
+
* signature verification.
|
|
64
|
+
*
|
|
65
|
+
* The JWKS client supports:
|
|
66
|
+
* - Automatic key retrieval
|
|
67
|
+
* - In-memory caching
|
|
68
|
+
* - Request rate limiting
|
|
69
|
+
*
|
|
70
|
+
* @async
|
|
71
|
+
* @function initOpenId
|
|
72
|
+
*
|
|
73
|
+
* @throws {Error} Throws if the OpenID configuration request fails
|
|
74
|
+
* or the response cannot be parsed.
|
|
75
|
+
*
|
|
76
|
+
* @returns {Promise<void>}
|
|
77
|
+
*/
|
|
78
|
+
export const initOpenId = async () => {
|
|
79
|
+
|
|
80
|
+
const response = await fetch(OPENID_CONFIG.url)
|
|
81
|
+
|
|
82
|
+
if ( !response.ok ) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`OpenID configuration endpoint failed with status "${response.status}"`
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const config = await response.json()
|
|
89
|
+
|
|
90
|
+
OPENID_CONFIG.issuer = config.issuer
|
|
91
|
+
|
|
92
|
+
OPENID_CONFIG.client = jwksClient({
|
|
93
|
+
...OPENID_CONFIG.jwksClient,
|
|
94
|
+
...{jwksUri: config.jwks_uri},
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Authorizes the requester by validating the access token.
|
|
102
|
+
* The token can be provided either in the Bearer Authorization header
|
|
103
|
+
* or in cookies.
|
|
104
|
+
*
|
|
105
|
+
* @param {Context} ctx - Moleculer service context
|
|
106
|
+
* @param {Object} route - REST route configuration object
|
|
107
|
+
* @param {HTTP request<Object>} req - HTTP request object
|
|
108
|
+
* @returns {Promise<Object>} Authenticated user / authorization result
|
|
109
|
+
*/
|
|
110
|
+
export const authorize = async (ctx, route, req) => {
|
|
111
|
+
|
|
112
|
+
let token = null
|
|
113
|
+
|
|
114
|
+
const auth =
|
|
115
|
+
req.headers.authorization
|
|
116
|
+
|
|
117
|
+
if (auth?.startsWith("Bearer ")) {
|
|
118
|
+
token = auth.replace(/^Bearer\s+/i, "")
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
!token &&
|
|
124
|
+
req.cookies?.id_token
|
|
125
|
+
) {
|
|
126
|
+
token = req.cookies.id_token
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!token) {
|
|
130
|
+
throw new ApiGateway.Errors.UnAuthorizedError(
|
|
131
|
+
ApiGateway.Errors.ERR_NO_TOKEN
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
|
|
137
|
+
const decoded =
|
|
138
|
+
await new Promise((resolve, reject) => {
|
|
139
|
+
|
|
140
|
+
jwt.verify(
|
|
141
|
+
token,
|
|
142
|
+
getKey,
|
|
143
|
+
{
|
|
144
|
+
algorithms: OPENID_CONFIG.jwtVerifyAlgo,
|
|
145
|
+
issuer: OPENID_CONFIG.issuer,
|
|
146
|
+
audience: OPENID_CONFIG.clientId,
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
(err, decoded) => {
|
|
150
|
+
|
|
151
|
+
if (err) {
|
|
152
|
+
reject(err)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
resolve(decoded)
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
ctx.broker.logger.debug({message: "Decoded Token Object", token: decoded})
|
|
162
|
+
ctx.meta.user = { name: decoded?.name, email: decoded?.email }
|
|
163
|
+
return decoded
|
|
164
|
+
|
|
165
|
+
} catch (err) {
|
|
166
|
+
throw new ApiGateway.Errors.UnAuthorizedError(
|
|
167
|
+
ApiGateway.Errors.ERR_INVALID_TOKEN
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
package/index.mjs
CHANGED
|
@@ -19,7 +19,6 @@ import HybridCacher from "#hMol/HybridCacher.mjs"
|
|
|
19
19
|
import about from '#sAbt/index.mjs'
|
|
20
20
|
import apiGateway from '#sApi/index.mjs'
|
|
21
21
|
import { auxBrokerParamsValidator } from '#hUti/aux-broker-params-validator.mjs'
|
|
22
|
-
|
|
23
22
|
import * as kafka from '#sKfk/index.mjs'
|
|
24
23
|
import * as demo from '#sDmo/index.mjs'
|
|
25
24
|
|
|
@@ -27,7 +26,6 @@ import * as demo from '#sDmo/index.mjs'
|
|
|
27
26
|
const BROKER_CONFIG = await getConfig('nats')
|
|
28
27
|
const CATCHER_CONFIG = await getConfig('catcher')
|
|
29
28
|
const TELEMETRY_CONFIG = await getConfig('telemetry')
|
|
30
|
-
const KAFKA_CONFIG = await getConfig('kafkajs')
|
|
31
29
|
|
|
32
30
|
const sbkLoggers = {
|
|
33
31
|
"CustomPino": customLogger
|
|
@@ -155,7 +153,7 @@ export default {
|
|
|
155
153
|
auxBroker = kafka
|
|
156
154
|
}
|
|
157
155
|
else {
|
|
158
|
-
throw new Error("The \"type\" value must be either \"kafka\" or \"mqtt\"
|
|
156
|
+
throw new Error("The \"type\" value must be either \"kafka\" or \"mqtt\" or \"amqp\"")
|
|
159
157
|
}
|
|
160
158
|
|
|
161
159
|
opts.logLevel = logLevel
|
|
@@ -179,7 +177,6 @@ export default {
|
|
|
179
177
|
)
|
|
180
178
|
}
|
|
181
179
|
|
|
182
|
-
|
|
183
180
|
/**
|
|
184
181
|
* Start broker
|
|
185
182
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "samanbayaka",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "Moleculer Gateway service with kafka transporter",
|
|
5
5
|
"homepage": "https://gitlab.com/dalal.suvendu/samanbayaka#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
"cookie-parser": "^1.4.7",
|
|
44
44
|
"helmet": "^8.1.0",
|
|
45
45
|
"ioredis": "^5.10.1",
|
|
46
|
+
"jsonwebtoken": "^9.0.3",
|
|
47
|
+
"jwks-rsa": "^4.0.1",
|
|
46
48
|
"kafkajs": "^2.2.4",
|
|
47
49
|
"lru-cache": "^11.3.5",
|
|
48
50
|
"moleculer": "0.15.0",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<button onclick="login()">Login with Google</button>
|
|
2
|
+
<button onclick="callAPI()">Call API</button>
|
|
3
|
+
|
|
4
|
+
<script>
|
|
5
|
+
const CLIENT_ID = "184045176764-fmdarpud3fkpojo5p73mloetgrqrg65p.apps.googleusercontent.com";
|
|
6
|
+
const REDIRECT_URI = "http://localhost:3000";
|
|
7
|
+
const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
8
|
+
const TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
9
|
+
|
|
10
|
+
// --- PKCE helpers ---
|
|
11
|
+
function generateRandomString(length) {
|
|
12
|
+
const chars =
|
|
13
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
14
|
+
let result = "";
|
|
15
|
+
for (let i = 0; i < length; i++) {
|
|
16
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function sha256(verifier) {
|
|
22
|
+
const encoder = new TextEncoder();
|
|
23
|
+
const data = encoder.encode(verifier);
|
|
24
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
25
|
+
return btoa(String.fromCharCode(...new Uint8Array(hash)))
|
|
26
|
+
.replace(/\+/g, "-")
|
|
27
|
+
.replace(/\//g, "_")
|
|
28
|
+
.replace(/=+$/, "");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// --- Step 1: login redirect ---
|
|
32
|
+
async function login() {
|
|
33
|
+
const codeVerifier = generateRandomString(64);
|
|
34
|
+
const codeChallenge = await sha256(codeVerifier);
|
|
35
|
+
|
|
36
|
+
localStorage.setItem("code_verifier", codeVerifier);
|
|
37
|
+
|
|
38
|
+
const url =
|
|
39
|
+
`${AUTH_URL}?response_type=code` +
|
|
40
|
+
`&client_id=${CLIENT_ID}` +
|
|
41
|
+
`&redirect_uri=${REDIRECT_URI}` +
|
|
42
|
+
`&scope=openid%20email%20profile` +
|
|
43
|
+
`&code_challenge=${codeChallenge}` +
|
|
44
|
+
`&code_challenge_method=S256`;
|
|
45
|
+
|
|
46
|
+
window.location = url;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- Step 2: handle redirect ---
|
|
50
|
+
async function handleRedirect() {
|
|
51
|
+
const params = new URLSearchParams(window.location.search);
|
|
52
|
+
const code = params.get("code");
|
|
53
|
+
|
|
54
|
+
if (!code) return;
|
|
55
|
+
|
|
56
|
+
const codeVerifier = localStorage.getItem("code_verifier");
|
|
57
|
+
|
|
58
|
+
const res = await fetch(TOKEN_URL, {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: {
|
|
61
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
62
|
+
},
|
|
63
|
+
body: new URLSearchParams({
|
|
64
|
+
client_id: CLIENT_ID,
|
|
65
|
+
grant_type: "authorization_code",
|
|
66
|
+
code,
|
|
67
|
+
code_verifier: codeVerifier,
|
|
68
|
+
redirect_uri: REDIRECT_URI,
|
|
69
|
+
}),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const data = await res.json();
|
|
73
|
+
|
|
74
|
+
console.log("Access Token:", data.access_token);
|
|
75
|
+
|
|
76
|
+
localStorage.setItem("access_token", data.access_token);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// --- Step 3: call API ---
|
|
80
|
+
async function callAPI() {
|
|
81
|
+
const token = localStorage.getItem("access_token");
|
|
82
|
+
|
|
83
|
+
const res = await fetch("http://localhost:4000/api/resource", {
|
|
84
|
+
headers: {
|
|
85
|
+
Authorization: `Bearer ${token}`,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(await res.json());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
handleRedirect();
|
|
93
|
+
</script>
|
package/services/about/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { pkgDtls } from '#hFil/esm-loading.mjs'
|
|
|
3
3
|
export default {
|
|
4
4
|
name: "about",
|
|
5
5
|
actions: {
|
|
6
|
-
|
|
6
|
+
project: {
|
|
7
7
|
rest: {
|
|
8
8
|
method: "GET",
|
|
9
9
|
path: "/"
|
|
@@ -34,5 +34,15 @@ export default {
|
|
|
34
34
|
return `${pkgDtls.fullName} ${pkgDtls.version}`
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
|
+
profile: {
|
|
38
|
+
rest: {
|
|
39
|
+
method: "GET",
|
|
40
|
+
path: "/me"
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
handler: async(ctx) => {
|
|
44
|
+
return ctx.meta.user
|
|
45
|
+
}
|
|
46
|
+
}
|
|
37
47
|
},
|
|
38
48
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { pkgDtls } from '#hFil/esm-loading.mjs'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
name: "bff",
|
|
5
|
+
actions: {
|
|
6
|
+
signin: {
|
|
7
|
+
rest: {
|
|
8
|
+
method: "GET",
|
|
9
|
+
path: "/signin"
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
handler: async(ctx) => {
|
|
13
|
+
return `Welcome to ${pkgDtls.name} is a microservices-based project built with moleculer and moleculer-web, designed for scalable, high-performance service communication and API management.`
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
callback: {
|
|
17
|
+
rest: {
|
|
18
|
+
method: "GET",
|
|
19
|
+
path: "/callback"
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
handler: async(ctx) => {
|
|
23
|
+
return `${pkgDtls.fullName} ${pkgDtls.version}`
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
signout: {
|
|
27
|
+
rest: {
|
|
28
|
+
method: "GET",
|
|
29
|
+
path: "/signout"
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
handler: async(ctx) => {
|
|
33
|
+
return ctx.meta.user
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// index.mjs
|
|
2
2
|
import ApiGateway from "moleculer-web"
|
|
3
3
|
import OpenApi from "moleculer-auto-openapi"
|
|
4
4
|
import cookieParser from "cookie-parser"
|
|
@@ -6,6 +6,7 @@ import helmet from "helmet"
|
|
|
6
6
|
import compression from "compression"
|
|
7
7
|
|
|
8
8
|
import {formatHttpErrors} from '#hUti/error-handler.mjs'
|
|
9
|
+
import { initOpenId, authorize } from '#hUti/access-token-validator.mjs'
|
|
9
10
|
|
|
10
11
|
export default {
|
|
11
12
|
name: "gateway",
|
|
@@ -13,6 +14,13 @@ export default {
|
|
|
13
14
|
ApiGateway,
|
|
14
15
|
],
|
|
15
16
|
|
|
17
|
+
async started() {
|
|
18
|
+
/**
|
|
19
|
+
* Initialize OpenID config
|
|
20
|
+
*/
|
|
21
|
+
await initOpenId()
|
|
22
|
+
},
|
|
23
|
+
|
|
16
24
|
settings: {
|
|
17
25
|
port: process.env.SBK_PORT || 8765,
|
|
18
26
|
|
|
@@ -42,14 +50,33 @@ export default {
|
|
|
42
50
|
|
|
43
51
|
|
|
44
52
|
routes: [
|
|
53
|
+
// Public routes
|
|
54
|
+
{
|
|
55
|
+
path: "/",
|
|
56
|
+
authorization: false,
|
|
57
|
+
|
|
58
|
+
whitelist: [
|
|
59
|
+
"bff.*",
|
|
60
|
+
],
|
|
61
|
+
|
|
62
|
+
autoAliases: true,
|
|
63
|
+
mappingPolicy: "restrict",
|
|
64
|
+
|
|
65
|
+
bodyParsers: {
|
|
66
|
+
json: true,
|
|
67
|
+
urlencoded: { extended: true }
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
|
|
45
71
|
/**
|
|
46
|
-
* API routes
|
|
72
|
+
* Protected API routes
|
|
47
73
|
*/
|
|
48
74
|
{
|
|
49
75
|
path: "/api",
|
|
76
|
+
authorization: true,
|
|
50
77
|
whitelist: [
|
|
51
78
|
/**
|
|
52
|
-
* Access any actions except 'system' service
|
|
79
|
+
* Access any actions except 'gateway' and 'system' service
|
|
53
80
|
*/
|
|
54
81
|
/^(?!(gateway|system)\.)\w+(?:\.\w+)*$/
|
|
55
82
|
],
|
|
@@ -124,6 +151,7 @@ export default {
|
|
|
124
151
|
// this.logger.error(" Request error!", err.name, ":", err.message, "\n", err.stack, "\nData:", err.data);
|
|
125
152
|
// }
|
|
126
153
|
this.sendError(req, res, err)
|
|
127
|
-
}
|
|
154
|
+
},
|
|
155
|
+
authorize,
|
|
128
156
|
},
|
|
129
157
|
}
|