@nestjs-kitchen/authz 3.0.1 → 4.0.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 +27 -8
- package/dist/authz.provider.d.ts +1 -2
- package/dist/jwt/jwt-authz-als.middleware.d.ts +5 -9
- package/dist/jwt/jwt-authz-als.middleware.js +6 -9
- package/dist/jwt/jwt-authz.guard.d.ts +10 -23
- package/dist/jwt/jwt-authz.guard.js +93 -22
- package/dist/jwt/jwt-authz.module.d.ts +6 -13
- package/dist/jwt/jwt-authz.module.js +3 -17
- package/dist/jwt/jwt-authz.service.d.ts +3 -3
- package/dist/session/session-authz-als.middleware.d.ts +3 -5
- package/dist/session/session-authz-als.middleware.js +29 -50
- package/dist/session/session-authz.guard.d.ts +3 -10
- package/dist/session/session-authz.guard.js +33 -11
- package/dist/session/session-authz.module.d.ts +4 -11
- package/dist/session/session-authz.module.js +1 -13
- package/dist/session/session-authz.service.d.ts +2 -2
- package/dist/utils/adapter-shim.d.ts +28 -0
- package/dist/utils/adapter-shim.js +174 -0
- package/dist/utils/cookie-parsers.d.ts +6 -7
- package/dist/utils/cookie-parsers.js +10 -0
- package/dist/utils/create-set-cookie-fn.d.ts +2 -3
- package/dist/utils/create-set-cookie-fn.js +2 -1
- package/dist/utils/generics.d.ts +0 -1
- package/dist/utils/generics.js +1 -12
- package/dist/utils/get-passport-property.d.ts +1 -1
- package/dist/utils/get-passport-property.js +0 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/safe-clone.d.ts +1 -0
- package/dist/utils/safe-clone.js +15 -0
- package/dist/utils/types.d.ts +0 -7
- package/package.json +24 -10
- package/dist/jwt/jwt-authz.strategy.d.ts +0 -17
- package/dist/jwt/jwt-authz.strategy.js +0 -134
- package/dist/session/session-authz.strategy.d.ts +0 -11
- package/dist/session/session-authz.strategy.js +0 -70
package/README.md
CHANGED
|
@@ -16,24 +16,43 @@ Simplest authentication & authorization module in NextJS.
|
|
|
16
16
|
|
|
17
17
|
## Features
|
|
18
18
|
|
|
19
|
-
- JWT
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
19
|
+
- ✅ Support JWT authentication
|
|
20
|
+
|
|
21
|
+
- ✅ Support session authentication
|
|
22
|
+
|
|
23
|
+
- ✅ Service based authentication/authorization -- Use Nestjs style services to implement authentication/authorization.
|
|
24
|
+
|
|
25
|
+
- ✅ Support Anonymous access
|
|
26
|
+
|
|
27
|
+
- ✅ Compatible with `Express` and `Fastify`
|
|
25
28
|
|
|
26
29
|
## Install
|
|
27
30
|
|
|
28
31
|
Once completed NestJS project setup, install this package and its dependencies:
|
|
29
32
|
|
|
30
33
|
```bash
|
|
31
|
-
$ npm install --save @nestjs
|
|
34
|
+
$ npm install --save @nestjs-kitchen/authz
|
|
32
35
|
```
|
|
33
36
|
|
|
37
|
+
## Platform support
|
|
38
|
+
|
|
39
|
+
Below platforms require different dependencies:
|
|
40
|
+
|
|
41
|
+
- For `@nestjs/platform-express`:
|
|
42
|
+
|
|
43
|
+
It requires [`express-session`](https://www.npmjs.com/package/express-session).
|
|
44
|
+
|
|
45
|
+
- For `@nestjs/platform-fastify`:
|
|
46
|
+
|
|
47
|
+
It requires [`@fastify/cookie`](https://www.npmjs.com/package/@fastify/cookie) and [`@fastify/session`](https://www.npmjs.com/package/@fastify/session).
|
|
48
|
+
|
|
49
|
+
Or [`@fastify/secure-session`](https://www.npmjs.com/package/@fastify/secure-session) instead.
|
|
50
|
+
|
|
34
51
|
## Beark change
|
|
35
52
|
|
|
36
|
-
- From
|
|
53
|
+
- From **v4**, `Passport.js` is moved out without any api changes.
|
|
54
|
+
|
|
55
|
+
- From **v3**, [`express-session`](https://www.npmjs.com/package/express-session) had been removed from dependency. Please setup session manually:
|
|
37
56
|
|
|
38
57
|
```typescript
|
|
39
58
|
import * as session from 'express-session';
|
package/dist/authz.provider.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Request } from 'express';
|
|
2
1
|
/**
|
|
3
2
|
* Abstract base class for implementing custom authorization logic.
|
|
4
3
|
*
|
|
@@ -26,7 +25,7 @@ export declare abstract class AuthzProviderClass<Payload, User> {
|
|
|
26
25
|
* @param {Payload} payload - The payload to authenticate.
|
|
27
26
|
* @returns {User | Promise<User>} The authenticated user, or a promise resolving to the user.
|
|
28
27
|
*/
|
|
29
|
-
abstract authenticate(payload: Payload, req?:
|
|
28
|
+
abstract authenticate(payload: Payload, req?: any): User | Promise<User>;
|
|
30
29
|
/**
|
|
31
30
|
* (**Optional**: Implement this method only if authorization is required.)
|
|
32
31
|
*
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { type Type } from '@nestjs/common';
|
|
3
|
-
import type { NextFunction, Request, Response } from 'express';
|
|
4
3
|
import { JwtValidationType } from '../constants';
|
|
5
|
-
import { type
|
|
6
|
-
import type { JwtAuthzOptions } from './jwt-authz.interface';
|
|
4
|
+
import { type RawRequestWithShims, type RawResponseWithShims } from '../utils';
|
|
7
5
|
export interface JwtAlsType<U> {
|
|
8
6
|
user?: U;
|
|
9
7
|
jwtVerifiedBy?: JwtValidationType;
|
|
10
8
|
allowAnonymous?: boolean;
|
|
11
9
|
guardResult?: boolean;
|
|
12
|
-
|
|
13
|
-
setCookie: (name: string, value: string, options?: CookieOptionsWithSecret) => void;
|
|
10
|
+
setCookie: (name: string, value: string, options?: Record<string, any>) => void;
|
|
14
11
|
}
|
|
15
|
-
export declare const createJwtAuthzAlsMiddleware: ([ALS_PROVIDER
|
|
12
|
+
export declare const createJwtAuthzAlsMiddleware: ([ALS_PROVIDER]: [any]) => Type<Omit<{
|
|
16
13
|
readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}, "als" | "jwtAuthzOptions">>;
|
|
14
|
+
use(req: RawRequestWithShims, res: RawResponseWithShims, next: Function): void;
|
|
15
|
+
}, "als">>;
|
|
@@ -16,30 +16,27 @@ exports.createJwtAuthzAlsMiddleware = void 0;
|
|
|
16
16
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
18
|
const utils_1 = require("../utils");
|
|
19
|
-
const createJwtAuthzAlsMiddleware = ([ALS_PROVIDER
|
|
19
|
+
const createJwtAuthzAlsMiddleware = ([ALS_PROVIDER]) => {
|
|
20
20
|
let JwtAuthzAlsMiddleware = class JwtAuthzAlsMiddleware {
|
|
21
|
-
constructor(als
|
|
21
|
+
constructor(als) {
|
|
22
22
|
this.als = als;
|
|
23
|
-
this.jwtAuthzOptions = jwtAuthzOptions;
|
|
24
23
|
}
|
|
25
24
|
use(req, res, next) {
|
|
26
|
-
|
|
25
|
+
const store = {
|
|
27
26
|
user: undefined,
|
|
28
27
|
jwtVerifiedBy: undefined,
|
|
29
28
|
allowAnonymous: undefined,
|
|
30
29
|
guardResult: undefined,
|
|
31
|
-
// a workaround to pass jwtAuthzOptions to passport strategy.
|
|
32
|
-
authOptions: this.jwtAuthzOptions,
|
|
33
30
|
setCookie: (0, utils_1.createSetCookieFn)(req, res)
|
|
34
|
-
}
|
|
31
|
+
};
|
|
32
|
+
this.als.run(store, () => {
|
|
35
33
|
next();
|
|
36
34
|
});
|
|
37
35
|
}
|
|
38
36
|
};
|
|
39
37
|
JwtAuthzAlsMiddleware = __decorate([
|
|
40
38
|
__param(0, (0, common_1.Inject)(ALS_PROVIDER)),
|
|
41
|
-
|
|
42
|
-
__metadata("design:paramtypes", [node_async_hooks_1.AsyncLocalStorage, Object])
|
|
39
|
+
__metadata("design:paramtypes", [node_async_hooks_1.AsyncLocalStorage])
|
|
43
40
|
], JwtAuthzAlsMiddleware);
|
|
44
41
|
return (0, common_1.mixin)(JwtAuthzAlsMiddleware);
|
|
45
42
|
};
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import type { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { ExecutionContext, type Type } from '@nestjs/common';
|
|
3
3
|
import { Reflector } from '@nestjs/core';
|
|
4
|
-
import type { Observable } from 'rxjs';
|
|
5
4
|
import { AuthzProviderClass } from '../authz.provider';
|
|
6
|
-
import {
|
|
5
|
+
import { AuthzError } from '../errors';
|
|
7
6
|
import type { JwtAuthzOptions } from './jwt-authz.interface';
|
|
8
7
|
import type { JwtAlsType } from './jwt-authz-als.middleware';
|
|
9
|
-
export declare const createJwtAuthzGuard: ([
|
|
8
|
+
export declare const createJwtAuthzGuard: ([AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, ALS_PROVIDER, JWT_META_KEY, JWT_REFRESH_META_KEY]: [any, any, any, any, any]) => Type<Omit<{
|
|
10
9
|
readonly reflector: Reflector;
|
|
11
10
|
readonly authzProvider: AuthzProviderClass<unknown, unknown>;
|
|
12
11
|
readonly jwtAuthzOptions: JwtAuthzOptions;
|
|
13
12
|
readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
|
|
14
|
-
getAuthenticateOptions(): {
|
|
15
|
-
property: string;
|
|
16
|
-
session: boolean;
|
|
17
|
-
};
|
|
18
13
|
/**
|
|
19
14
|
*
|
|
20
15
|
* recives err, user, info from JwtStrategy.validate
|
|
@@ -28,21 +23,13 @@ export declare const createJwtAuthzGuard: ([JWT_STRATEGY, AUTHZ_PROVIDER, JWT_AU
|
|
|
28
23
|
*/
|
|
29
24
|
handleRequest<T>(_err: unknown, user: T, info?: AuthzError): T;
|
|
30
25
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
getRequest(context: ExecutionContext): any;
|
|
35
|
-
}, "als" | "jwtAuthzOptions" | "reflector" | "authzProvider">>;
|
|
36
|
-
export declare const createJwtRefreshAuthzGuard: ([JWT_REFRESH_STRATEGY, JWT_AUTHZ_OPTIONS]: [string, any]) => Type<Omit<{
|
|
26
|
+
validate(req: any): Promise<[any, any?]>;
|
|
27
|
+
}, "als" | "reflector" | "authzProvider" | "jwtAuthzOptions">>;
|
|
28
|
+
export declare const createJwtRefreshAuthzGuard: ([JWT_AUTHZ_OPTIONS, AUTHZ_PROVIDER, ALS_PROVIDER]: [any, any, any]) => Type<Omit<{
|
|
37
29
|
readonly jwtAuthzOptions: JwtAuthzOptions;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
session: boolean;
|
|
41
|
-
};
|
|
30
|
+
readonly authzProvider: AuthzProviderClass<unknown, unknown>;
|
|
31
|
+
readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
|
|
42
32
|
handleRequest<T>(_err: unknown, user: T, info?: AuthzError): T;
|
|
43
|
-
canActivate(context: ExecutionContext):
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} = any>(request: TRequest): Promise<void>;
|
|
47
|
-
getRequest(context: ExecutionContext): any;
|
|
48
|
-
}, "jwtAuthzOptions">>;
|
|
33
|
+
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
34
|
+
validate(req: any): Promise<[any, any?]>;
|
|
35
|
+
}, "als" | "authzProvider" | "jwtAuthzOptions">>;
|
|
@@ -11,28 +11,29 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
12
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
13
|
};
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
14
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
18
|
exports.createJwtRefreshAuthzGuard = exports.createJwtAuthzGuard = void 0;
|
|
16
19
|
const common_1 = require("@nestjs/common");
|
|
17
20
|
const core_1 = require("@nestjs/core");
|
|
18
|
-
const
|
|
21
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
19
22
|
const authz_provider_1 = require("../authz.provider");
|
|
23
|
+
const constants_1 = require("../constants");
|
|
20
24
|
const errors_1 = require("../errors");
|
|
21
25
|
const utils_1 = require("../utils");
|
|
22
|
-
const
|
|
23
|
-
|
|
26
|
+
const extract_jwt_1 = require("./extract-jwt");
|
|
27
|
+
const createJwtAuthzGuard = ([AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, ALS_PROVIDER, JWT_META_KEY, JWT_REFRESH_META_KEY]) => {
|
|
28
|
+
let JwtAuthzGuard = class JwtAuthzGuard {
|
|
24
29
|
constructor(reflector, authzProvider, jwtAuthzOptions, als) {
|
|
25
|
-
super();
|
|
26
30
|
this.reflector = reflector;
|
|
27
31
|
this.authzProvider = authzProvider;
|
|
28
32
|
this.jwtAuthzOptions = jwtAuthzOptions;
|
|
29
33
|
this.als = als;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
property: this.jwtAuthzOptions.passportProperty,
|
|
34
|
-
session: false
|
|
35
|
-
};
|
|
34
|
+
if (typeof this.authzProvider.authenticate !== 'function') {
|
|
35
|
+
throw new errors_1.AuthzError(`InternalError: Method 'authenticate' from abstract class 'AuthzProvider' must be implemented.`);
|
|
36
|
+
}
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
38
39
|
*
|
|
@@ -82,7 +83,7 @@ const createJwtAuthzGuard = ([JWT_STRATEGY, AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, A
|
|
|
82
83
|
store.allowAnonymous = (0, utils_1.getAllowAnonymous)(contextParamsList, {
|
|
83
84
|
defaultAllowAnonymous: this.jwtAuthzOptions.defaultAllowAnonymous
|
|
84
85
|
});
|
|
85
|
-
await
|
|
86
|
+
req[this.jwtAuthzOptions.passportProperty] = this.handleRequest(undefined, ...(await this.validate(req)));
|
|
86
87
|
// will be null if allowAnonymous=true.
|
|
87
88
|
const user = (0, utils_1.getPassportProperty)(req);
|
|
88
89
|
if (store.allowAnonymous && !user) {
|
|
@@ -95,6 +96,38 @@ const createJwtAuthzGuard = ([JWT_STRATEGY, AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, A
|
|
|
95
96
|
}
|
|
96
97
|
return true;
|
|
97
98
|
}
|
|
99
|
+
async validate(req) {
|
|
100
|
+
const store = (0, utils_1.getAlsStore)(this.als);
|
|
101
|
+
const authOptions = this.jwtAuthzOptions;
|
|
102
|
+
if (!authOptions.jwt.verify) {
|
|
103
|
+
return [null, new errors_1.AuthzError(`InternalError: Refresh verify options must be implemented.`)];
|
|
104
|
+
}
|
|
105
|
+
const extractor = extract_jwt_1.ExtractJwt.fromExtractors(authOptions.jwt.jwtFromRequest);
|
|
106
|
+
req[constants_1.PASSPORT_PROPERTY] = authOptions.passportProperty;
|
|
107
|
+
const token = extractor(req);
|
|
108
|
+
if (!token) {
|
|
109
|
+
return [null, new errors_1.AuthzAnonymousError('AnonymousError: Cannnot find token.')];
|
|
110
|
+
}
|
|
111
|
+
let user = undefined;
|
|
112
|
+
try {
|
|
113
|
+
const payload = jsonwebtoken_1.default.verify(token, authOptions.jwt.secretOrPublicKey, authOptions.jwt.verify);
|
|
114
|
+
user = await this.authzProvider.authenticate(payload, req);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
return [
|
|
118
|
+
null,
|
|
119
|
+
error instanceof Error
|
|
120
|
+
? new errors_1.AuthzVerificationError(`${error.name}: ${error.message}`, error)
|
|
121
|
+
: new errors_1.AuthzVerificationError(`${error}`)
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
store.user = user;
|
|
125
|
+
store.jwtVerifiedBy = constants_1.JwtValidationType.JWT;
|
|
126
|
+
if (!user) {
|
|
127
|
+
return [null, new errors_1.AuthzAnonymousError('AnonymousError: Cannnot find user.')];
|
|
128
|
+
}
|
|
129
|
+
return [user];
|
|
130
|
+
}
|
|
98
131
|
};
|
|
99
132
|
JwtAuthzGuard = __decorate([
|
|
100
133
|
__param(1, (0, common_1.Inject)(AUTHZ_PROVIDER)),
|
|
@@ -106,17 +139,15 @@ const createJwtAuthzGuard = ([JWT_STRATEGY, AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, A
|
|
|
106
139
|
return (0, common_1.mixin)(JwtAuthzGuard);
|
|
107
140
|
};
|
|
108
141
|
exports.createJwtAuthzGuard = createJwtAuthzGuard;
|
|
109
|
-
const createJwtRefreshAuthzGuard = ([
|
|
110
|
-
let JwtRefreshAuthzGuard = class JwtRefreshAuthzGuard
|
|
111
|
-
constructor(jwtAuthzOptions) {
|
|
112
|
-
super();
|
|
142
|
+
const createJwtRefreshAuthzGuard = ([JWT_AUTHZ_OPTIONS, AUTHZ_PROVIDER, ALS_PROVIDER]) => {
|
|
143
|
+
let JwtRefreshAuthzGuard = class JwtRefreshAuthzGuard {
|
|
144
|
+
constructor(jwtAuthzOptions, authzProvider, als) {
|
|
113
145
|
this.jwtAuthzOptions = jwtAuthzOptions;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
};
|
|
146
|
+
this.authzProvider = authzProvider;
|
|
147
|
+
this.als = als;
|
|
148
|
+
if (typeof this.authzProvider.authenticate !== 'function') {
|
|
149
|
+
throw new errors_1.AuthzError(`InternalError: Method 'authenticate' from abstract class 'AuthzProvider' must be implemented.`);
|
|
150
|
+
}
|
|
120
151
|
}
|
|
121
152
|
handleRequest(_err, user, info) {
|
|
122
153
|
if (info) {
|
|
@@ -124,10 +155,50 @@ const createJwtRefreshAuthzGuard = ([JWT_REFRESH_STRATEGY, JWT_AUTHZ_OPTIONS]) =
|
|
|
124
155
|
}
|
|
125
156
|
return user;
|
|
126
157
|
}
|
|
158
|
+
async canActivate(context) {
|
|
159
|
+
const req = context.switchToHttp().getRequest();
|
|
160
|
+
req[this.jwtAuthzOptions.passportProperty] = this.handleRequest(undefined, ...(await this.validate(req)));
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
async validate(req) {
|
|
164
|
+
const store = (0, utils_1.getAlsStore)(this.als);
|
|
165
|
+
const authOptions = this.jwtAuthzOptions;
|
|
166
|
+
if (!authOptions.refresh.verify) {
|
|
167
|
+
return [null, new errors_1.AuthzError(`InternalError: Refresh verify options must be implemented.`)];
|
|
168
|
+
}
|
|
169
|
+
const extractor = extract_jwt_1.ExtractJwt.fromExtractors(authOptions.refresh.jwtFromRequest);
|
|
170
|
+
req[constants_1.PASSPORT_PROPERTY] = authOptions.passportProperty;
|
|
171
|
+
const token = extractor(req);
|
|
172
|
+
if (!token) {
|
|
173
|
+
return [null, new errors_1.AuthzAnonymousError('AnonymousError: Cannnot find token.')];
|
|
174
|
+
}
|
|
175
|
+
let user = undefined;
|
|
176
|
+
try {
|
|
177
|
+
const payload = jsonwebtoken_1.default.verify(token, authOptions.refresh.secretOrPublicKey, authOptions.refresh.verify);
|
|
178
|
+
const decodePayload = (0, utils_1.decodeMsgpackrString)(payload.data);
|
|
179
|
+
user = await this.authzProvider.authenticate(decodePayload, req);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
return [
|
|
183
|
+
null,
|
|
184
|
+
error instanceof Error
|
|
185
|
+
? new errors_1.AuthzVerificationError(`${error.name}: ${error.message}`, error)
|
|
186
|
+
: new errors_1.AuthzVerificationError(`${error}`)
|
|
187
|
+
];
|
|
188
|
+
}
|
|
189
|
+
store.user = user;
|
|
190
|
+
store.jwtVerifiedBy = constants_1.JwtValidationType.REFRESH;
|
|
191
|
+
if (!user) {
|
|
192
|
+
return [null, new errors_1.AuthzAnonymousError('AnonymousError: Cannnot find user.')];
|
|
193
|
+
}
|
|
194
|
+
return [user];
|
|
195
|
+
}
|
|
127
196
|
};
|
|
128
197
|
JwtRefreshAuthzGuard = __decorate([
|
|
129
198
|
__param(0, (0, common_1.Inject)(JWT_AUTHZ_OPTIONS)),
|
|
130
|
-
|
|
199
|
+
__param(1, (0, common_1.Inject)(AUTHZ_PROVIDER)),
|
|
200
|
+
__param(2, (0, common_1.Inject)(ALS_PROVIDER)),
|
|
201
|
+
__metadata("design:paramtypes", [Object, authz_provider_1.AuthzProviderClass, Function])
|
|
131
202
|
], JwtRefreshAuthzGuard);
|
|
132
203
|
return (0, common_1.mixin)(JwtRefreshAuthzGuard);
|
|
133
204
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { type ConfigurableModuleAsyncOptions, DynamicModule, type ExecutionContext, MiddlewareConsumer, type Type } from '@nestjs/common';
|
|
3
|
-
import type
|
|
3
|
+
import { type Reflector } from '@nestjs/core';
|
|
4
4
|
import { AuthzProviderClass } from '../authz.provider';
|
|
5
5
|
import { AuthzError } from '../errors';
|
|
6
|
-
import { type AbstractConstructor, type ApplyDecorators, type AuthzDecoParams, type AuthzModuleBaseOptions, type AuthzModuleRoutesOptions, type
|
|
6
|
+
import { type AbstractConstructor, type ApplyDecorators, type AuthzDecoParams, type AuthzModuleBaseOptions, type AuthzModuleRoutesOptions, type DeepReadonly, type MethodParameters, type RoutesOptions } from '../utils';
|
|
7
7
|
import { type JwtAuthzModuleOptions, type JwtAuthzOptions, type JwtOptions } from './jwt-authz.interface';
|
|
8
8
|
import { type JwtAlsType } from './jwt-authz-als.middleware';
|
|
9
9
|
declare const ASYNC_OPTIONS_TYPE: ConfigurableModuleAsyncOptions<JwtAuthzModuleOptions, "createJwtAuthzModuleOptions"> & Partial<{
|
|
@@ -97,17 +97,10 @@ export declare const createJwtAuthzModule: <P, U, T extends AuthzProviderClass<P
|
|
|
97
97
|
readonly authzProvider: AuthzProviderClass<unknown, unknown>;
|
|
98
98
|
readonly jwtAuthzOptions: JwtAuthzOptions;
|
|
99
99
|
readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
|
|
100
|
-
getAuthenticateOptions(): {
|
|
101
|
-
property: string;
|
|
102
|
-
session: boolean;
|
|
103
|
-
};
|
|
104
100
|
handleRequest<T_1>(_err: unknown, user: T_1, info?: AuthzError): T_1;
|
|
105
101
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
} = any>(request: TRequest): Promise<void>;
|
|
109
|
-
getRequest(context: ExecutionContext): any;
|
|
110
|
-
}, "als" | "jwtAuthzOptions" | "reflector" | "authzProvider">> & {
|
|
102
|
+
validate(req: any): Promise<[any, any?]>;
|
|
103
|
+
}, "als" | "reflector" | "authzProvider" | "jwtAuthzOptions">> & {
|
|
111
104
|
/**
|
|
112
105
|
* Verifies the user's authorization for specific meta data.
|
|
113
106
|
*
|
|
@@ -197,8 +190,8 @@ export declare const createJwtAuthzModule: <P, U, T extends AuthzProviderClass<P
|
|
|
197
190
|
refresh(user?: U | undefined): Promise<{
|
|
198
191
|
token: string;
|
|
199
192
|
} | undefined>;
|
|
200
|
-
setCookie(name: string, value: string, options?:
|
|
193
|
+
setCookie(name: string, value: string, options?: Record<string, any> | undefined): void;
|
|
201
194
|
getUser(): DeepReadonly<U> | undefined;
|
|
202
|
-
}, "als" | "
|
|
195
|
+
}, "als" | "authzProvider" | "jwtAuthzOptions">>;
|
|
203
196
|
};
|
|
204
197
|
export {};
|
|
@@ -22,7 +22,6 @@ const utils_1 = require("../utils");
|
|
|
22
22
|
const jwt_authz_guard_1 = require("./jwt-authz.guard");
|
|
23
23
|
const jwt_authz_interface_1 = require("./jwt-authz.interface");
|
|
24
24
|
const jwt_authz_service_1 = require("./jwt-authz.service");
|
|
25
|
-
const jwt_authz_strategy_1 = require("./jwt-authz.strategy");
|
|
26
25
|
const jwt_authz_als_middleware_1 = require("./jwt-authz-als.middleware");
|
|
27
26
|
const store = {
|
|
28
27
|
globalInited: 0
|
|
@@ -53,6 +52,7 @@ const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, ASYNC_OPTIONS_TYPE, OPTIO
|
|
|
53
52
|
return (0, utils_1.mergeDynamicModuleConfigs)(definition, {
|
|
54
53
|
global,
|
|
55
54
|
providers: [
|
|
55
|
+
...(0, utils_1.createOnceAdapterShimProvider)(),
|
|
56
56
|
{
|
|
57
57
|
provide: constants_1.ROUTES_OPTIONS,
|
|
58
58
|
useValue: {
|
|
@@ -76,9 +76,6 @@ const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, ASYNC_OPTIONS_TYPE, OPTIO
|
|
|
76
76
|
const createJwtAuthzModule = (authzProvider) => {
|
|
77
77
|
// prevent token overriding
|
|
78
78
|
const id = `${constants_1.PREFIX}${(0, uid_1.uid)()}`;
|
|
79
|
-
// strategy tokens
|
|
80
|
-
const JWT_STRATEGY = `${id}_JWT_STRATEGY`;
|
|
81
|
-
const JWT_REFRESH_STRATEGY = `${id}_REFRESH_STRATEGY`;
|
|
82
79
|
// provider tokens
|
|
83
80
|
const AUTHZ_PROVIDER = `${id}_AUTHZ_PROVIDER`;
|
|
84
81
|
const ALS_PROVIDER = `${id}_ALS_PROVIDER`;
|
|
@@ -88,20 +85,11 @@ const createJwtAuthzModule = (authzProvider) => {
|
|
|
88
85
|
const JWT_REFRESH_META_KEY = `${id}_REFRESH_META_KEY`;
|
|
89
86
|
// providers
|
|
90
87
|
const JwtAuthzService = (0, jwt_authz_service_1.createJwtAuthzService)([AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, ALS_PROVIDER]);
|
|
91
|
-
const JwtAuthzAlsMiddleware = (0, jwt_authz_als_middleware_1.createJwtAuthzAlsMiddleware)([ALS_PROVIDER
|
|
88
|
+
const JwtAuthzAlsMiddleware = (0, jwt_authz_als_middleware_1.createJwtAuthzAlsMiddleware)([ALS_PROVIDER]);
|
|
92
89
|
const als = new node_async_hooks_1.AsyncLocalStorage();
|
|
93
|
-
// strategy
|
|
94
|
-
const JwtStrategy = (0, jwt_authz_strategy_1.createJwtStrategy)([JWT_STRATEGY, AUTHZ_PROVIDER, ALS_PROVIDER]);
|
|
95
|
-
const RefreshStrategy = (0, jwt_authz_strategy_1.createRefreshStrategy)([JWT_REFRESH_STRATEGY, AUTHZ_PROVIDER, ALS_PROVIDER]);
|
|
96
|
-
// each strategy can be only registered once in passport.
|
|
97
|
-
// no need to provide multiple times as
|
|
98
|
-
// 1. they use the same ALS and authzProvider instance.
|
|
99
|
-
// 2. guard use strategy through passport via strategy name.
|
|
100
|
-
let isStrategyInited = false;
|
|
101
90
|
// guards
|
|
102
|
-
const RefreshAuthzGuard = (0, jwt_authz_guard_1.createJwtRefreshAuthzGuard)([
|
|
91
|
+
const RefreshAuthzGuard = (0, jwt_authz_guard_1.createJwtRefreshAuthzGuard)([JWT_AUTHZ_OPTIONS, AUTHZ_PROVIDER, ALS_PROVIDER]);
|
|
103
92
|
const JwtAuthzGuard = (0, jwt_authz_guard_1.createJwtAuthzGuard)([
|
|
104
|
-
JWT_STRATEGY,
|
|
105
93
|
AUTHZ_PROVIDER,
|
|
106
94
|
JWT_AUTHZ_OPTIONS,
|
|
107
95
|
ALS_PROVIDER,
|
|
@@ -135,12 +123,10 @@ const createJwtAuthzModule = (authzProvider) => {
|
|
|
135
123
|
provide: ALS_PROVIDER,
|
|
136
124
|
useValue: als
|
|
137
125
|
},
|
|
138
|
-
...(!isStrategyInited ? [JwtStrategy, RefreshStrategy] : []),
|
|
139
126
|
JwtAuthzService
|
|
140
127
|
],
|
|
141
128
|
exports: [AUTHZ_PROVIDER, ALS_PROVIDER, JWT_AUTHZ_OPTIONS, JwtAuthzService]
|
|
142
129
|
};
|
|
143
|
-
isStrategyInited = true;
|
|
144
130
|
return configs;
|
|
145
131
|
};
|
|
146
132
|
let JwtAuthzModule = class JwtAuthzModule extends ConfigurableModuleClass {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { type Type } from '@nestjs/common';
|
|
3
3
|
import { AuthzProviderClass } from '../authz.provider';
|
|
4
|
-
import { type
|
|
4
|
+
import { type DeepReadonly } from '../utils';
|
|
5
5
|
import type { JwtAuthzOptions } from './jwt-authz.interface';
|
|
6
6
|
import type { JwtAlsType } from './jwt-authz-als.middleware';
|
|
7
7
|
export declare const createJwtAuthzService: <P = unknown, U = unknown>([AUTHZ_PROVIDER, JWT_AUTHZ_OPTIONS, ALS_PROVIDER]: [any, any, any]) => Type<Omit<{
|
|
@@ -36,9 +36,9 @@ export declare const createJwtAuthzService: <P = unknown, U = unknown>([AUTHZ_PR
|
|
|
36
36
|
/**
|
|
37
37
|
* Sets a secure HTTP cookie with the given name, value, and optional cookie options.
|
|
38
38
|
*/
|
|
39
|
-
setCookie(name: string, value: string, options?:
|
|
39
|
+
setCookie(name: string, value: string, options?: Record<string, any> | undefined): void;
|
|
40
40
|
/**
|
|
41
41
|
* Retrieves the current user associated with the request, if available.
|
|
42
42
|
*/
|
|
43
43
|
getUser(): DeepReadonly<U> | undefined;
|
|
44
|
-
}, "als" | "
|
|
44
|
+
}, "als" | "authzProvider" | "jwtAuthzOptions">>;
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
import { type Type } from '@nestjs/common';
|
|
3
|
-
import
|
|
4
|
-
import { type CookieOptionsWithSecret } from '../utils';
|
|
3
|
+
import { type RawRequestWithShims, type RawResponseWithShims } from '../utils';
|
|
5
4
|
import type { SessionAuthzOptions } from './session-authz.interface';
|
|
6
5
|
export interface SessionAlsType<P, U> {
|
|
7
6
|
user?: U;
|
|
8
7
|
allowAnonymous?: boolean;
|
|
9
8
|
guardResult?: boolean;
|
|
10
|
-
authOptions: SessionAuthzOptions;
|
|
11
9
|
logIn: (user: P) => Promise<void>;
|
|
12
10
|
logOut: () => Promise<void>;
|
|
13
|
-
setCookie: (name: string, value: string, options?:
|
|
11
|
+
setCookie: (name: string, value: string, options?: Record<string, any>) => void;
|
|
14
12
|
}
|
|
15
13
|
export declare const createSessionAuthzAlsMiddleware: ([ALS_PROVIDER, SESSION_AUTHZ_OPTIONS]: [any, any]) => Type<Omit<{
|
|
16
14
|
readonly als: AsyncLocalStorage<SessionAlsType<unknown, unknown>>;
|
|
17
15
|
readonly sessionAuthzOptions: SessionAuthzOptions;
|
|
18
|
-
use(req:
|
|
16
|
+
use(req: RawRequestWithShims, res: RawResponseWithShims, next: Function): void;
|
|
19
17
|
}, "als" | "sessionAuthzOptions">>;
|
|
@@ -16,7 +16,6 @@ exports.createSessionAuthzAlsMiddleware = void 0;
|
|
|
16
16
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
17
17
|
const common_1 = require("@nestjs/common");
|
|
18
18
|
const constants_1 = require("../constants");
|
|
19
|
-
const errors_1 = require("../errors");
|
|
20
19
|
const utils_1 = require("../utils");
|
|
21
20
|
const createSessionAuthzAlsMiddleware = ([ALS_PROVIDER, SESSION_AUTHZ_OPTIONS]) => {
|
|
22
21
|
let SessionAuthzAlsMiddleware = class SessionAuthzAlsMiddleware {
|
|
@@ -26,64 +25,44 @@ const createSessionAuthzAlsMiddleware = ([ALS_PROVIDER, SESSION_AUTHZ_OPTIONS])
|
|
|
26
25
|
}
|
|
27
26
|
use(req, res, next) {
|
|
28
27
|
const keepSessionInfo = Boolean(this.sessionAuthzOptions.keepSessionInfo);
|
|
29
|
-
if (!req.session) {
|
|
30
|
-
return next(new errors_1.AuthzError('Login sessions require session support. Did you forget to use `express-session` middleware?'));
|
|
31
|
-
}
|
|
32
|
-
const prevSession = req.session;
|
|
33
28
|
const store = {
|
|
34
29
|
user: undefined,
|
|
35
30
|
allowAnonymous: undefined,
|
|
36
31
|
guardResult: undefined,
|
|
37
|
-
authOptions: this.sessionAuthzOptions,
|
|
38
32
|
// ref: https://github.com/jaredhanson/passport/blob/217018dbc46dcd4118dd6f2c60c8d97010c587f8/lib/sessionmanager.js#L14
|
|
39
|
-
logIn: (user) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
logIn: async (user) => {
|
|
34
|
+
const prevSession = req.shims.getAllSession();
|
|
35
|
+
await req.shims.regenerateSession();
|
|
36
|
+
if (keepSessionInfo) {
|
|
37
|
+
for (const key in prevSession) {
|
|
38
|
+
if (req.shims.sessionContains(key)) {
|
|
39
|
+
req.shims.setSession(key, prevSession[key]);
|
|
44
40
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
req.session[constants_1.SESSION_PASSPORT_KEY].user = user;
|
|
55
|
-
req.session.save(function (err) {
|
|
56
|
-
if (err) {
|
|
57
|
-
return reject(err);
|
|
58
|
-
}
|
|
59
|
-
resolve();
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const passportSession = req.shims.getSession(constants_1.SESSION_PASSPORT_KEY) ?? {};
|
|
44
|
+
passportSession.user = user;
|
|
45
|
+
req.shims.setSession(constants_1.SESSION_PASSPORT_KEY, passportSession);
|
|
46
|
+
await req.shims.saveSession();
|
|
47
|
+
return;
|
|
63
48
|
},
|
|
64
49
|
// ref: https://github.com/jaredhanson/passport/blob/217018dbc46dcd4118dd6f2c60c8d97010c587f8/lib/sessionmanager.js#L57
|
|
65
|
-
logOut: () => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
50
|
+
logOut: async () => {
|
|
51
|
+
if (req.shims.sessionContains(constants_1.SESSION_PASSPORT_KEY)) {
|
|
52
|
+
const passportSession = req.shims.getSession(constants_1.SESSION_PASSPORT_KEY);
|
|
53
|
+
delete passportSession.user;
|
|
54
|
+
req.shims.setSession(constants_1.SESSION_PASSPORT_KEY, passportSession);
|
|
55
|
+
}
|
|
56
|
+
const prevSession = req.shims.getAllSession();
|
|
57
|
+
await req.shims.saveSession();
|
|
58
|
+
await req.shims.regenerateSession();
|
|
59
|
+
if (keepSessionInfo) {
|
|
60
|
+
for (const key in prevSession) {
|
|
61
|
+
if (req.shims.sessionContains(key)) {
|
|
62
|
+
req.shims.setSession(key, prevSession[key]);
|
|
75
63
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return reject(err);
|
|
79
|
-
}
|
|
80
|
-
if (keepSessionInfo) {
|
|
81
|
-
(0, utils_1.merge)(req.session, prevSession);
|
|
82
|
-
}
|
|
83
|
-
resolve();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
87
66
|
},
|
|
88
67
|
setCookie: (0, utils_1.createSetCookieFn)(req, res)
|
|
89
68
|
};
|
|
@@ -2,18 +2,14 @@ import { ExecutionContext, type Type } from '@nestjs/common';
|
|
|
2
2
|
import { Reflector } from '@nestjs/core';
|
|
3
3
|
import type { AsyncLocalStorage } from 'async_hooks';
|
|
4
4
|
import { AuthzProviderClass } from '../authz.provider';
|
|
5
|
-
import {
|
|
5
|
+
import { AuthzError } from '../errors';
|
|
6
6
|
import type { SessionAuthzOptions } from './session-authz.interface';
|
|
7
7
|
import type { SessionAlsType } from './session-authz-als.middleware';
|
|
8
|
-
export declare const createSessionAuthzGuard: ([
|
|
8
|
+
export declare const createSessionAuthzGuard: ([AUTHZ_PROVIDER, SESSION_AUTHZ_OPTIONS, ALS_PROVIDER, SESSION_META_KEY]: [any, any, any, any]) => Type<Omit<{
|
|
9
9
|
readonly reflector: Reflector;
|
|
10
10
|
readonly authzProvider: AuthzProviderClass<unknown, unknown>;
|
|
11
11
|
readonly sessionAuthzOptions: SessionAuthzOptions;
|
|
12
12
|
readonly als: AsyncLocalStorage<SessionAlsType<unknown, unknown>>;
|
|
13
|
-
getAuthenticateOptions(): {
|
|
14
|
-
property: string;
|
|
15
|
-
session: boolean;
|
|
16
|
-
};
|
|
17
13
|
/**
|
|
18
14
|
*
|
|
19
15
|
* recives err, user, info from JwtStrategy.validate
|
|
@@ -27,8 +23,5 @@ export declare const createSessionAuthzGuard: ([SESSION_STRATEGY, AUTHZ_PROVIDER
|
|
|
27
23
|
*/
|
|
28
24
|
handleRequest<T>(_err: unknown, user: T, info?: AuthzError): T;
|
|
29
25
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
30
|
-
|
|
31
|
-
logIn: Function;
|
|
32
|
-
} = any>(request: TRequest): Promise<void>;
|
|
33
|
-
getRequest(context: ExecutionContext): any;
|
|
26
|
+
validate(req: any): Promise<[any, any?]>;
|
|
34
27
|
}, "als" | "reflector" | "authzProvider" | "sessionAuthzOptions">>;
|