@nocobase/auth 2.2.0-beta.9 → 3.0.0-alpha.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/lib/actions.d.ts +1 -1
- package/lib/actions.js +27 -1
- package/lib/auth-manager.d.ts +1 -0
- package/lib/auth-manager.js +69 -7
- package/lib/auth.d.ts +3 -1
- package/lib/auth.js +18 -4
- package/lib/base/auth.d.ts +8 -0
- package/lib/base/auth.js +121 -0
- package/package.json +7 -7
package/lib/actions.d.ts
CHANGED
|
@@ -6,5 +6,5 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
-
import { Handlers } from '@nocobase/resourcer';
|
|
9
|
+
import type { Handlers } from '@nocobase/resourcer';
|
|
10
10
|
export declare const actions: Handlers;
|
package/lib/actions.js
CHANGED
|
@@ -30,7 +30,28 @@ __export(actions_exports, {
|
|
|
30
30
|
actions: () => actions
|
|
31
31
|
});
|
|
32
32
|
module.exports = __toCommonJS(actions_exports);
|
|
33
|
+
var import_utils = require("@nocobase/utils");
|
|
33
34
|
/* istanbul ignore file -- @preserve */
|
|
35
|
+
const localeNamespace = "auth";
|
|
36
|
+
function assertTrustedSignInOrigin(ctx) {
|
|
37
|
+
const originContext = {
|
|
38
|
+
protocol: ctx.protocol,
|
|
39
|
+
headers: ctx.headers,
|
|
40
|
+
get: /* @__PURE__ */ __name((name) => ctx.get(name), "get")
|
|
41
|
+
};
|
|
42
|
+
const origin = ctx.get("origin");
|
|
43
|
+
if (origin) {
|
|
44
|
+
if (!(0, import_utils.isTrustedOrigin)(originContext, origin)) {
|
|
45
|
+
ctx.throw(403, ctx.t("Invalid sign-in origin", { ns: localeNamespace }));
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const refererOrigin = (0, import_utils.getOrigin)(ctx.get("referer"));
|
|
50
|
+
if (refererOrigin && !(0, import_utils.isTrustedOrigin)(originContext, refererOrigin)) {
|
|
51
|
+
ctx.throw(403, ctx.t("Invalid sign-in origin", { ns: localeNamespace }));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
__name(assertTrustedSignInOrigin, "assertTrustedSignInOrigin");
|
|
34
55
|
function filterHiddenFields(ctx, user) {
|
|
35
56
|
var _a, _b;
|
|
36
57
|
if (!user) {
|
|
@@ -51,6 +72,7 @@ function filterHiddenFields(ctx, user) {
|
|
|
51
72
|
__name(filterHiddenFields, "filterHiddenFields");
|
|
52
73
|
const actions = {
|
|
53
74
|
signIn: /* @__PURE__ */ __name(async (ctx, next) => {
|
|
75
|
+
assertTrustedSignInOrigin(ctx);
|
|
54
76
|
ctx.body = await ctx.auth.signIn();
|
|
55
77
|
await next();
|
|
56
78
|
}, "signIn"),
|
|
@@ -66,7 +88,11 @@ const actions = {
|
|
|
66
88
|
check: /* @__PURE__ */ __name(async (ctx, next) => {
|
|
67
89
|
ctx.body = filterHiddenFields(ctx, ctx.auth.user);
|
|
68
90
|
await next();
|
|
69
|
-
}, "check")
|
|
91
|
+
}, "check"),
|
|
92
|
+
syncCookies: /* @__PURE__ */ __name(async (ctx, next) => {
|
|
93
|
+
ctx.body = await ctx.auth.syncCookies();
|
|
94
|
+
await next();
|
|
95
|
+
}, "syncCookies")
|
|
70
96
|
};
|
|
71
97
|
// Annotate the CommonJS export names for ESM import in node:
|
|
72
98
|
0 && (module.exports = {
|
package/lib/auth-manager.d.ts
CHANGED
package/lib/auth-manager.js
CHANGED
|
@@ -37,7 +37,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
37
37
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
38
|
var auth_manager_exports = {};
|
|
39
39
|
__export(auth_manager_exports, {
|
|
40
|
-
AuthManager: () => AuthManager
|
|
40
|
+
AuthManager: () => AuthManager,
|
|
41
|
+
csrfMiddleware: () => csrfMiddleware
|
|
41
42
|
});
|
|
42
43
|
module.exports = __toCommonJS(auth_manager_exports);
|
|
43
44
|
var import_utils = require("@nocobase/utils");
|
|
@@ -45,6 +46,7 @@ var import_jwt_service = require("./base/jwt-service");
|
|
|
45
46
|
var import_path = __toESM(require("path"));
|
|
46
47
|
var import_fs = __toESM(require("fs"));
|
|
47
48
|
var import_crypto = __toESM(require("crypto"));
|
|
49
|
+
const SAFE_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
|
|
48
50
|
const _AuthManager = class _AuthManager {
|
|
49
51
|
/**
|
|
50
52
|
* @internal
|
|
@@ -144,23 +146,66 @@ const _AuthManager = class _AuthManager {
|
|
|
144
146
|
middleware() {
|
|
145
147
|
const self = this;
|
|
146
148
|
return /* @__PURE__ */ __name(async function AuthManagerMiddleware(ctx, next) {
|
|
147
|
-
|
|
149
|
+
var _a, _b;
|
|
150
|
+
const headerAuthenticator = ctx.get(self.options.authKey);
|
|
151
|
+
const cookieName = (0, import_utils.getAuthCookieName)("authenticator", ctx.app.name);
|
|
152
|
+
const cookieAuthenticator = headerAuthenticator ? null : ctx.cookies.get(cookieName);
|
|
153
|
+
const name = headerAuthenticator || cookieAuthenticator || self.options.default;
|
|
148
154
|
let authenticator;
|
|
149
155
|
try {
|
|
150
156
|
authenticator = await ctx.app.authManager.get(name, ctx);
|
|
151
157
|
ctx.auth = authenticator;
|
|
152
158
|
} catch (err) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
if (cookieAuthenticator && !headerAuthenticator && self.options.default && name !== self.options.default) {
|
|
160
|
+
ctx.cookies.set(cookieName, null, (0, import_utils.getAuthCookieOptions)(ctx));
|
|
161
|
+
try {
|
|
162
|
+
authenticator = await ctx.app.authManager.get(self.options.default, ctx);
|
|
163
|
+
ctx.auth = authenticator;
|
|
164
|
+
} catch (defaultErr) {
|
|
165
|
+
ctx.auth = {};
|
|
166
|
+
ctx.logger.warn(defaultErr.message, { method: "check", authenticator: self.options.default });
|
|
167
|
+
return next();
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
ctx.auth = {};
|
|
171
|
+
ctx.logger.warn(err.message, { method: "check", authenticator: name });
|
|
172
|
+
return next();
|
|
173
|
+
}
|
|
156
174
|
}
|
|
157
175
|
if (!authenticator) {
|
|
176
|
+
ctx.auth = {};
|
|
158
177
|
return next();
|
|
159
178
|
}
|
|
160
179
|
if (await ctx.auth.skipCheck()) {
|
|
161
180
|
return next();
|
|
162
181
|
}
|
|
163
|
-
|
|
182
|
+
let user;
|
|
183
|
+
try {
|
|
184
|
+
user = await ctx.auth.check();
|
|
185
|
+
} catch (err) {
|
|
186
|
+
if (((_a = ctx.state) == null ? void 0 : _a.optionalAuth) === true && ((_b = ctx.state) == null ? void 0 : _b.pendingAuthTokenSource) === "cookie" && (err.status === 401 || err.statusCode === 401)) {
|
|
187
|
+
const authTokenCookieName = (0, import_utils.getAuthCookieName)("authToken", ctx.app.name);
|
|
188
|
+
const authCookieOptions = (0, import_utils.getAuthCookieOptions)(ctx);
|
|
189
|
+
ctx.cookies.set(authTokenCookieName, null, authCookieOptions);
|
|
190
|
+
const rawPublicPath = process.env.APP_PUBLIC_PATH;
|
|
191
|
+
if (rawPublicPath && rawPublicPath !== authCookieOptions.path) {
|
|
192
|
+
ctx.cookies.set(authTokenCookieName, null, { ...authCookieOptions, path: rawPublicPath });
|
|
193
|
+
}
|
|
194
|
+
ctx.state.currentUser = void 0;
|
|
195
|
+
ctx.state.authTokenSource = void 0;
|
|
196
|
+
ctx.state.pendingAuthTokenSource = void 0;
|
|
197
|
+
try {
|
|
198
|
+
return await next();
|
|
199
|
+
} catch (anonymousErr) {
|
|
200
|
+
const setCookieHeader = ctx.res.getHeader("set-cookie");
|
|
201
|
+
if (setCookieHeader) {
|
|
202
|
+
anonymousErr.headers = { ...anonymousErr.headers, "set-cookie": setCookieHeader };
|
|
203
|
+
}
|
|
204
|
+
throw anonymousErr;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
164
209
|
if (user) {
|
|
165
210
|
ctx.auth.user = user;
|
|
166
211
|
}
|
|
@@ -192,7 +237,24 @@ const _AuthManager = class _AuthManager {
|
|
|
192
237
|
};
|
|
193
238
|
__name(_AuthManager, "AuthManager");
|
|
194
239
|
let AuthManager = _AuthManager;
|
|
240
|
+
async function csrfMiddleware(ctx, next) {
|
|
241
|
+
var _a, _b;
|
|
242
|
+
if (SAFE_METHODS.has(ctx.method)) {
|
|
243
|
+
return next();
|
|
244
|
+
}
|
|
245
|
+
if (((_a = ctx.state) == null ? void 0 : _a.authTokenSource) !== "cookie" || !((_b = ctx.state) == null ? void 0 : _b.currentUser)) {
|
|
246
|
+
return next();
|
|
247
|
+
}
|
|
248
|
+
const cookieToken = ctx.cookies.get((0, import_utils.getAuthCookieName)("csrfToken", ctx.app.name));
|
|
249
|
+
const headerToken = ctx.get("X-CSRF-Token");
|
|
250
|
+
if (!cookieToken || cookieToken.length < 16 || headerToken !== cookieToken) {
|
|
251
|
+
return ctx.throw(403, ctx.t("Invalid CSRF token", { ns: "auth" }));
|
|
252
|
+
}
|
|
253
|
+
await next();
|
|
254
|
+
}
|
|
255
|
+
__name(csrfMiddleware, "csrfMiddleware");
|
|
195
256
|
// Annotate the CommonJS export names for ESM import in node:
|
|
196
257
|
0 && (module.exports = {
|
|
197
|
-
AuthManager
|
|
258
|
+
AuthManager,
|
|
259
|
+
csrfMiddleware
|
|
198
260
|
});
|
package/lib/auth.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ interface IAuth {
|
|
|
41
41
|
signIn(): Promise<any>;
|
|
42
42
|
signUp(): Promise<any>;
|
|
43
43
|
signOut(): Promise<any>;
|
|
44
|
+
syncCookies(): Promise<unknown>;
|
|
44
45
|
}
|
|
45
46
|
export declare abstract class Auth implements IAuth {
|
|
46
47
|
/**
|
|
@@ -54,7 +55,7 @@ export declare abstract class Auth implements IAuth {
|
|
|
54
55
|
};
|
|
55
56
|
protected ctx: Context;
|
|
56
57
|
constructor(config: AuthConfig);
|
|
57
|
-
skipCheck(): Promise<
|
|
58
|
+
skipCheck(): Promise<boolean>;
|
|
58
59
|
abstract check(): Promise<Model>;
|
|
59
60
|
abstract checkToken(): Promise<{
|
|
60
61
|
tokenStatus: 'valid' | 'expired' | 'invalid';
|
|
@@ -67,5 +68,6 @@ export declare abstract class Auth implements IAuth {
|
|
|
67
68
|
signIn(): Promise<any>;
|
|
68
69
|
signUp(): Promise<any>;
|
|
69
70
|
signOut(): Promise<any>;
|
|
71
|
+
syncCookies(): Promise<unknown>;
|
|
70
72
|
}
|
|
71
73
|
export {};
|
package/lib/auth.js
CHANGED
|
@@ -64,17 +64,28 @@ const _Auth = class _Auth {
|
|
|
64
64
|
this.ctx = ctx;
|
|
65
65
|
}
|
|
66
66
|
async skipCheck() {
|
|
67
|
+
var _a, _b;
|
|
67
68
|
if (this.ctx.skipAuthCheck === true) {
|
|
68
69
|
return true;
|
|
69
70
|
}
|
|
71
|
+
const { resourceName, actionName } = this.ctx.action;
|
|
72
|
+
const acl = this.ctx.dataSource.acl;
|
|
73
|
+
const isPublic = await acl.allowManager.isPublic(resourceName, actionName, this.ctx);
|
|
74
|
+
if (isPublic) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
const hasExplicitToken = Boolean(this.ctx.get("Authorization") || this.ctx.query.token);
|
|
78
|
+
if (!hasExplicitToken && this.ctx.app.options.acl === false && ((_a = this.ctx.state) == null ? void 0 : _a.optionalAuth) !== true) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
70
81
|
const token = this.ctx.getBearerToken();
|
|
82
|
+
if (!token && ((_b = this.ctx.state) == null ? void 0 : _b.optionalAuth) === true) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
71
85
|
if (!token && this.ctx.app.options.acl === false) {
|
|
72
86
|
return true;
|
|
73
87
|
}
|
|
74
|
-
|
|
75
|
-
const acl = this.ctx.dataSource.acl;
|
|
76
|
-
const isPublic = await acl.allowManager.isPublic(resourceName, actionName, this.ctx);
|
|
77
|
-
return isPublic;
|
|
88
|
+
return false;
|
|
78
89
|
}
|
|
79
90
|
// The following methods are mainly designed for user authentications.
|
|
80
91
|
async signIn() {
|
|
@@ -83,6 +94,9 @@ const _Auth = class _Auth {
|
|
|
83
94
|
}
|
|
84
95
|
async signOut() {
|
|
85
96
|
}
|
|
97
|
+
async syncCookies() {
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
86
100
|
};
|
|
87
101
|
__name(_Auth, "Auth");
|
|
88
102
|
/**
|
package/lib/base/auth.d.ts
CHANGED
|
@@ -25,6 +25,11 @@ export declare class BaseAuth extends Auth {
|
|
|
25
25
|
*/
|
|
26
26
|
get jwt(): JwtService;
|
|
27
27
|
get tokenController(): ITokenControlService;
|
|
28
|
+
protected get appName(): any;
|
|
29
|
+
protected getSessionCookieMaxAge(): Promise<number>;
|
|
30
|
+
protected setAuthCookies(token: string, maxAge?: number): void;
|
|
31
|
+
protected setSessionCookies(user: Model, maxAge?: number): Promise<void>;
|
|
32
|
+
protected clearAuthCookies(): void;
|
|
28
33
|
set user(user: Model);
|
|
29
34
|
get user(): Model;
|
|
30
35
|
/**
|
|
@@ -50,5 +55,8 @@ export declare class BaseAuth extends Auth {
|
|
|
50
55
|
user: Model<any, any>;
|
|
51
56
|
token: string;
|
|
52
57
|
}>;
|
|
58
|
+
syncCookies(): Promise<{
|
|
59
|
+
synced: true;
|
|
60
|
+
}>;
|
|
53
61
|
signOut(): Promise<any>;
|
|
54
62
|
}
|
package/lib/base/auth.js
CHANGED
|
@@ -40,6 +40,8 @@ __export(auth_exports, {
|
|
|
40
40
|
BaseAuth: () => BaseAuth
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(auth_exports);
|
|
43
|
+
var import_utils = require("@nocobase/utils");
|
|
44
|
+
var import_crypto = __toESM(require("crypto"));
|
|
43
45
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
44
46
|
var import_auth = require("../auth");
|
|
45
47
|
const localeNamespace = "auth";
|
|
@@ -62,6 +64,100 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
62
64
|
get tokenController() {
|
|
63
65
|
return this.ctx.app.authManager.tokenController;
|
|
64
66
|
}
|
|
67
|
+
get appName() {
|
|
68
|
+
var _a;
|
|
69
|
+
return ((_a = this.ctx.app) == null ? void 0 : _a.name) || "main";
|
|
70
|
+
}
|
|
71
|
+
async getSessionCookieMaxAge() {
|
|
72
|
+
var _a, _b, _c;
|
|
73
|
+
try {
|
|
74
|
+
return (_a = await this.tokenController.getConfig()) == null ? void 0 : _a.sessionExpirationTime;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
(_c = (_b = this.ctx.logger) == null ? void 0 : _b.warn) == null ? void 0 : _c.call(_b, error, { method: "auth.getSessionCookieMaxAge" });
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
setAuthCookies(token, maxAge) {
|
|
81
|
+
var _a;
|
|
82
|
+
if (!this.ctx.cookies) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const options = (0, import_utils.getAuthCookieOptions)(this.ctx, true, maxAge);
|
|
86
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("authToken", this.appName), token, options);
|
|
87
|
+
if ((_a = this.authenticator) == null ? void 0 : _a.name) {
|
|
88
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("authenticator", this.appName), this.authenticator.name, options);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async setSessionCookies(user, maxAge) {
|
|
92
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
93
|
+
if (!this.ctx.cookies) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.ctx.cookies.set(
|
|
97
|
+
(0, import_utils.getAuthCookieName)("csrfToken", this.appName),
|
|
98
|
+
import_crypto.default.randomBytes(24).toString("base64url"),
|
|
99
|
+
(0, import_utils.getAuthCookieOptions)(this.ctx, false, maxAge)
|
|
100
|
+
);
|
|
101
|
+
const currentRole = (_a = this.ctx.state) == null ? void 0 : _a.currentRole;
|
|
102
|
+
let roleName = typeof currentRole === "string" ? currentRole : (_c = (_b = this.ctx).get) == null ? void 0 : _c.call(_b, "X-Role");
|
|
103
|
+
const userId = typeof user.get === "function" ? user.get("id") : user.id;
|
|
104
|
+
if (!roleName) {
|
|
105
|
+
try {
|
|
106
|
+
const rolesUser = await ((_f = (_e = (_d = this.ctx.db) == null ? void 0 : _d.getRepository) == null ? void 0 : _e.call(_d, "rolesUsers")) == null ? void 0 : _f.findOne({
|
|
107
|
+
where: {
|
|
108
|
+
userId,
|
|
109
|
+
default: true
|
|
110
|
+
},
|
|
111
|
+
raw: true
|
|
112
|
+
}));
|
|
113
|
+
roleName = rolesUser == null ? void 0 : rolesUser.roleName;
|
|
114
|
+
} catch {
|
|
115
|
+
roleName = void 0;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (!roleName) {
|
|
119
|
+
try {
|
|
120
|
+
const roles = await ((_i = (_h = (_g = this.ctx.db) == null ? void 0 : _g.getRepository) == null ? void 0 : _h.call(_g, "users.roles", userId)) == null ? void 0 : _i.find({
|
|
121
|
+
raw: true
|
|
122
|
+
}));
|
|
123
|
+
roleName = (_j = roles == null ? void 0 : roles[0]) == null ? void 0 : _j.name;
|
|
124
|
+
} catch {
|
|
125
|
+
roleName = void 0;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (!roleName) {
|
|
129
|
+
try {
|
|
130
|
+
if (typeof user.getRoles === "function") {
|
|
131
|
+
roleName = (_l = (_k = await user.getRoles({ raw: true })) == null ? void 0 : _k[0]) == null ? void 0 : _l.name;
|
|
132
|
+
} else if (userId) {
|
|
133
|
+
const userModel = await this.userRepository.findOne({
|
|
134
|
+
filter: { id: userId }
|
|
135
|
+
});
|
|
136
|
+
roleName = (_o = (_n = await ((_m = userModel == null ? void 0 : userModel.getRoles) == null ? void 0 : _m.call(userModel, { raw: true }))) == null ? void 0 : _n[0]) == null ? void 0 : _o.name;
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
(_q = (_p = this.ctx.logger) == null ? void 0 : _p.warn) == null ? void 0 : _q.call(_p, error, { method: "auth.setSessionCookies" });
|
|
140
|
+
roleName = void 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (roleName) {
|
|
144
|
+
this.ctx.cookies.set(
|
|
145
|
+
(0, import_utils.getAuthCookieName)("role", this.appName),
|
|
146
|
+
roleName,
|
|
147
|
+
(0, import_utils.getAuthCookieOptions)(this.ctx, false, maxAge)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
clearAuthCookies() {
|
|
152
|
+
if (!this.ctx.cookies) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const options = (0, import_utils.getAuthCookieOptions)(this.ctx);
|
|
156
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("authToken", this.appName), null, options);
|
|
157
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("authenticator", this.appName), null, options);
|
|
158
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("role", this.appName), null, (0, import_utils.getAuthCookieOptions)(this.ctx, false));
|
|
159
|
+
this.ctx.cookies.set((0, import_utils.getAuthCookieName)("csrfToken", this.appName), null, (0, import_utils.getAuthCookieOptions)(this.ctx, false));
|
|
160
|
+
}
|
|
65
161
|
set user(user) {
|
|
66
162
|
this.ctx.state.currentUser = user;
|
|
67
163
|
}
|
|
@@ -83,7 +179,9 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
83
179
|
async checkToken() {
|
|
84
180
|
var _a, _b, _c;
|
|
85
181
|
const cache = this.ctx.cache;
|
|
182
|
+
this.ctx.state = this.ctx.state || {};
|
|
86
183
|
const token = this.ctx.getBearerToken();
|
|
184
|
+
const tokenSource = this.ctx.state.pendingAuthTokenSource;
|
|
87
185
|
if (!token) {
|
|
88
186
|
this.ctx.throw(401, {
|
|
89
187
|
message: this.ctx.t("Unauthenticated. Please sign in to continue.", { ns: localeNamespace }),
|
|
@@ -136,6 +234,7 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
136
234
|
}
|
|
137
235
|
if (!temp) {
|
|
138
236
|
if (tokenStatus === "valid") {
|
|
237
|
+
this.ctx.state.authTokenSource = tokenSource;
|
|
139
238
|
return { tokenStatus, user, temp };
|
|
140
239
|
} else {
|
|
141
240
|
this.ctx.throw(401, {
|
|
@@ -185,8 +284,10 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
185
284
|
code: import_auth.AuthErrorCode.INVALID_TOKEN
|
|
186
285
|
});
|
|
187
286
|
}
|
|
287
|
+
this.ctx.state.authTokenSource = tokenSource;
|
|
188
288
|
return { tokenStatus, user, jti, signInTime, temp };
|
|
189
289
|
}
|
|
290
|
+
this.ctx.state.authTokenSource = tokenSource;
|
|
190
291
|
return { tokenStatus, user, jti, signInTime, temp };
|
|
191
292
|
}
|
|
192
293
|
async check() {
|
|
@@ -224,6 +325,7 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
224
325
|
{ jwtid: renewedResult.jti, expiresIn }
|
|
225
326
|
);
|
|
226
327
|
this.ctx.res.setHeader("x-new-token", newToken);
|
|
328
|
+
this.setAuthCookies(newToken, tokenPolicy.sessionExpirationTime);
|
|
227
329
|
} catch (err) {
|
|
228
330
|
this.ctx.logger.error("token renew failed", {
|
|
229
331
|
method: "auth.check",
|
|
@@ -275,12 +377,31 @@ const _BaseAuth = class _BaseAuth extends import_auth.Auth {
|
|
|
275
377
|
});
|
|
276
378
|
}
|
|
277
379
|
const token = await this.signNewToken(user.id);
|
|
380
|
+
const maxAge = await this.getSessionCookieMaxAge();
|
|
381
|
+
this.setAuthCookies(token, maxAge);
|
|
382
|
+
await this.setSessionCookies(user, maxAge);
|
|
278
383
|
return {
|
|
279
384
|
user,
|
|
280
385
|
token
|
|
281
386
|
};
|
|
282
387
|
}
|
|
388
|
+
async syncCookies() {
|
|
389
|
+
const tokenHeader = this.ctx.res.getHeader("x-new-token");
|
|
390
|
+
const token = typeof tokenHeader === "string" ? tokenHeader : this.ctx.getBearerToken();
|
|
391
|
+
const user = this.user || this.ctx.state.currentUser;
|
|
392
|
+
if (!token || !user) {
|
|
393
|
+
this.ctx.throw(401, {
|
|
394
|
+
message: this.ctx.t("Unauthenticated. Please sign in to continue.", { ns: localeNamespace }),
|
|
395
|
+
code: import_auth.AuthErrorCode.EMPTY_TOKEN
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
const maxAge = await this.getSessionCookieMaxAge();
|
|
399
|
+
this.setAuthCookies(token, maxAge);
|
|
400
|
+
await this.setSessionCookies(user, maxAge);
|
|
401
|
+
return { synced: true };
|
|
402
|
+
}
|
|
283
403
|
async signOut() {
|
|
404
|
+
this.clearAuthCookies();
|
|
284
405
|
const token = this.ctx.getBearerToken();
|
|
285
406
|
if (!token) {
|
|
286
407
|
return;
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/auth",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0-alpha.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@nocobase/actions": "
|
|
10
|
-
"@nocobase/cache": "
|
|
11
|
-
"@nocobase/database": "
|
|
12
|
-
"@nocobase/resourcer": "
|
|
13
|
-
"@nocobase/utils": "
|
|
9
|
+
"@nocobase/actions": "3.0.0-alpha.1",
|
|
10
|
+
"@nocobase/cache": "3.0.0-alpha.1",
|
|
11
|
+
"@nocobase/database": "3.0.0-alpha.1",
|
|
12
|
+
"@nocobase/resourcer": "3.0.0-alpha.1",
|
|
13
|
+
"@nocobase/utils": "3.0.0-alpha.1",
|
|
14
14
|
"@types/jsonwebtoken": "^9.0.9",
|
|
15
15
|
"jsonwebtoken": "^9.0.2"
|
|
16
16
|
},
|
|
@@ -19,5 +19,5 @@
|
|
|
19
19
|
"url": "git+https://github.com/nocobase/nocobase.git",
|
|
20
20
|
"directory": "packages/auth"
|
|
21
21
|
},
|
|
22
|
-
"gitHead": "
|
|
22
|
+
"gitHead": "22d8be8ece179cfa5c8a4ebb2c896c92bd418e03"
|
|
23
23
|
}
|