@nocobase/plugin-auth 0.10.0-alpha.2
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 +117 -0
- package/client.d.ts +3 -0
- package/client.js +65 -0
- package/lib/client/basic/Options.d.ts +2 -0
- package/lib/client/basic/Options.js +51 -0
- package/lib/client/basic/SigninPage.d.ts +6 -0
- package/lib/client/basic/SigninPage.js +100 -0
- package/lib/client/basic/SignupPage.d.ts +5 -0
- package/lib/client/basic/SignupPage.js +131 -0
- package/lib/client/index.d.ts +3 -0
- package/lib/client/index.js +56 -0
- package/lib/client/locale/index.d.ts +2 -0
- package/lib/client/locale/index.js +19 -0
- package/lib/client/locale/zh-CN.d.ts +9 -0
- package/lib/client/locale/zh-CN.js +16 -0
- package/lib/client/settings/Authenticator.d.ts +2 -0
- package/lib/client/settings/Authenticator.js +159 -0
- package/lib/client/settings/Options.d.ts +3 -0
- package/lib/client/settings/Options.js +56 -0
- package/lib/client/settings/authType.d.ts +16 -0
- package/lib/client/settings/authType.js +27 -0
- package/lib/client/settings/schemas/authenticators.d.ts +3 -0
- package/lib/client/settings/schemas/authenticators.js +438 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +20 -0
- package/lib/preset.d.ts +3 -0
- package/lib/preset.js +12 -0
- package/lib/server/actions/auth.d.ts +8 -0
- package/lib/server/actions/auth.js +51 -0
- package/lib/server/actions/authenticators.d.ts +8 -0
- package/lib/server/actions/authenticators.js +131 -0
- package/lib/server/basic-auth.d.ts +10 -0
- package/lib/server/basic-auth.js +183 -0
- package/lib/server/collections/authenticators.d.ts +6 -0
- package/lib/server/collections/authenticators.js +93 -0
- package/lib/server/collections/users-authenticators.d.ts +7 -0
- package/lib/server/collections/users-authenticators.js +75 -0
- package/lib/server/index.d.ts +2 -0
- package/lib/server/index.js +20 -0
- package/lib/server/locale/en-US.d.ts +9 -0
- package/lib/server/locale/en-US.js +15 -0
- package/lib/server/locale/index.d.ts +3 -0
- package/lib/server/locale/index.js +27 -0
- package/lib/server/locale/ja-JP.d.ts +5 -0
- package/lib/server/locale/ja-JP.js +11 -0
- package/lib/server/locale/pt-BR.d.ts +9 -0
- package/lib/server/locale/pt-BR.js +15 -0
- package/lib/server/locale/zh-CN.d.ts +10 -0
- package/lib/server/locale/zh-CN.js +16 -0
- package/lib/server/migrations/20230506152253-basic-authenticator.d.ts +5 -0
- package/lib/server/migrations/20230506152253-basic-authenticator.js +40 -0
- package/lib/server/migrations/20230607174500-update-basic.d.ts +5 -0
- package/lib/server/migrations/20230607174500-update-basic.js +43 -0
- package/lib/server/model/authenticator.d.ts +6 -0
- package/lib/server/model/authenticator.js +72 -0
- package/lib/server/plugin.d.ts +11 -0
- package/lib/server/plugin.js +130 -0
- package/package.json +17 -0
- package/server.d.ts +3 -0
- package/server.js +65 -0
- package/src/client/basic/Options.tsx +31 -0
- package/src/client/basic/SigninPage.tsx +65 -0
- package/src/client/basic/SignupPage.tsx +91 -0
- package/src/client/index.tsx +41 -0
- package/src/client/locale/index.ts +7 -0
- package/src/client/locale/zh-CN.ts +10 -0
- package/src/client/settings/Authenticator.tsx +95 -0
- package/src/client/settings/Options.tsx +35 -0
- package/src/client/settings/authType.ts +18 -0
- package/src/client/settings/schemas/authenticators.ts +402 -0
- package/src/index.ts +1 -0
- package/src/preset.ts +4 -0
- package/src/server/__tests__/actions.test.ts +142 -0
- package/src/server/actions/auth.ts +20 -0
- package/src/server/actions/authenticators.ts +85 -0
- package/src/server/basic-auth.ts +128 -0
- package/src/server/collections/.gitkeep +0 -0
- package/src/server/collections/authenticators.ts +97 -0
- package/src/server/collections/users-authenticators.ts +73 -0
- package/src/server/index.ts +2 -0
- package/src/server/locale/en-US.ts +10 -0
- package/src/server/locale/index.ts +3 -0
- package/src/server/locale/ja-JP.ts +4 -0
- package/src/server/locale/pt-BR.ts +10 -0
- package/src/server/locale/zh-CN.ts +9 -0
- package/src/server/migrations/20230506152253-basic-authenticator.ts +22 -0
- package/src/server/migrations/20230607174500-update-basic.ts +25 -0
- package/src/server/model/authenticator.ts +48 -0
- package/src/server/plugin.ts +92 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.AuthModel = void 0;
|
|
7
|
+
function _database() {
|
|
8
|
+
const data = require("@nocobase/database");
|
|
9
|
+
_database = function _database() {
|
|
10
|
+
return data;
|
|
11
|
+
};
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
15
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
16
|
+
class AuthModel extends _database().Model {
|
|
17
|
+
findUser(uuid) {
|
|
18
|
+
var _this = this;
|
|
19
|
+
return _asyncToGenerator(function* () {
|
|
20
|
+
let user;
|
|
21
|
+
const users = yield _this.getUsers({
|
|
22
|
+
through: {
|
|
23
|
+
where: {
|
|
24
|
+
uuid
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (users.length) {
|
|
29
|
+
user = users[0];
|
|
30
|
+
return user;
|
|
31
|
+
}
|
|
32
|
+
})();
|
|
33
|
+
}
|
|
34
|
+
newUser(uuid, values) {
|
|
35
|
+
var _this2 = this;
|
|
36
|
+
return _asyncToGenerator(function* () {
|
|
37
|
+
let user;
|
|
38
|
+
const db = _this2.constructor.database;
|
|
39
|
+
yield _this2.sequelize.transaction( /*#__PURE__*/function () {
|
|
40
|
+
var _ref = _asyncToGenerator(function* (transaction) {
|
|
41
|
+
// Create a new user if not exists
|
|
42
|
+
user = yield _this2.createUser(values || {
|
|
43
|
+
nickname: uuid
|
|
44
|
+
}, {
|
|
45
|
+
through: {
|
|
46
|
+
uuid: uuid
|
|
47
|
+
},
|
|
48
|
+
transaction
|
|
49
|
+
});
|
|
50
|
+
yield db.emitAsync(`users.afterCreateWithAssociations`, user, {
|
|
51
|
+
transaction
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return function (_x) {
|
|
55
|
+
return _ref.apply(this, arguments);
|
|
56
|
+
};
|
|
57
|
+
}());
|
|
58
|
+
return user;
|
|
59
|
+
})();
|
|
60
|
+
}
|
|
61
|
+
findOrCreateUser(uuid, userValues) {
|
|
62
|
+
var _this3 = this;
|
|
63
|
+
return _asyncToGenerator(function* () {
|
|
64
|
+
const user = yield _this3.findUser(uuid);
|
|
65
|
+
if (user) {
|
|
66
|
+
return user;
|
|
67
|
+
}
|
|
68
|
+
return yield _this3.newUser(uuid, userValues);
|
|
69
|
+
})();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.AuthModel = AuthModel;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InstallOptions, Plugin } from '@nocobase/server';
|
|
2
|
+
export declare class AuthPlugin extends Plugin {
|
|
3
|
+
afterAdd(): void;
|
|
4
|
+
beforeLoad(): Promise<void>;
|
|
5
|
+
load(): Promise<void>;
|
|
6
|
+
install(options?: InstallOptions): Promise<void>;
|
|
7
|
+
afterEnable(): Promise<void>;
|
|
8
|
+
afterDisable(): Promise<void>;
|
|
9
|
+
remove(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export default AuthPlugin;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.AuthPlugin = void 0;
|
|
7
|
+
function _server() {
|
|
8
|
+
const data = require("@nocobase/server");
|
|
9
|
+
_server = function _server() {
|
|
10
|
+
return data;
|
|
11
|
+
};
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
function _path() {
|
|
15
|
+
const data = require("path");
|
|
16
|
+
_path = function _path() {
|
|
17
|
+
return data;
|
|
18
|
+
};
|
|
19
|
+
return data;
|
|
20
|
+
}
|
|
21
|
+
var _basicAuth = require("./basic-auth");
|
|
22
|
+
var _preset = require("../preset");
|
|
23
|
+
var _auth = _interopRequireDefault(require("./actions/auth"));
|
|
24
|
+
var _authenticators = _interopRequireDefault(require("./actions/authenticators"));
|
|
25
|
+
var _locale = require("./locale");
|
|
26
|
+
var _authenticator = require("./model/authenticator");
|
|
27
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
|
+
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
29
|
+
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
30
|
+
class AuthPlugin extends _server().Plugin {
|
|
31
|
+
afterAdd() {}
|
|
32
|
+
beforeLoad() {
|
|
33
|
+
var _this = this;
|
|
34
|
+
return _asyncToGenerator(function* () {
|
|
35
|
+
_this.app.i18n.addResources('zh-CN', _preset.namespace, _locale.zhCN);
|
|
36
|
+
_this.app.i18n.addResources('en-US', _preset.namespace, _locale.enUS);
|
|
37
|
+
_this.app.db.registerModels({
|
|
38
|
+
AuthModel: _authenticator.AuthModel
|
|
39
|
+
});
|
|
40
|
+
})();
|
|
41
|
+
}
|
|
42
|
+
load() {
|
|
43
|
+
var _this2 = this;
|
|
44
|
+
return _asyncToGenerator(function* () {
|
|
45
|
+
// Set up database
|
|
46
|
+
yield _this2.db.import({
|
|
47
|
+
directory: (0, _path().resolve)(__dirname, 'collections')
|
|
48
|
+
});
|
|
49
|
+
_this2.db.addMigrations({
|
|
50
|
+
namespace: 'auth',
|
|
51
|
+
directory: (0, _path().resolve)(__dirname, 'migrations'),
|
|
52
|
+
context: {
|
|
53
|
+
plugin: _this2
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
// Set up auth manager and register preset auth type
|
|
57
|
+
_this2.app.authManager.setStorer({
|
|
58
|
+
get: function () {
|
|
59
|
+
var _get = _asyncToGenerator(function* (name) {
|
|
60
|
+
const repo = _this2.db.getRepository('authenticators');
|
|
61
|
+
const authenticators = yield repo.find({
|
|
62
|
+
filter: {
|
|
63
|
+
enabled: true
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const authenticator = authenticators.find(authenticator => authenticator.name === name);
|
|
67
|
+
return authenticator || authenticators[0];
|
|
68
|
+
});
|
|
69
|
+
function get(_x) {
|
|
70
|
+
return _get.apply(this, arguments);
|
|
71
|
+
}
|
|
72
|
+
return get;
|
|
73
|
+
}()
|
|
74
|
+
});
|
|
75
|
+
_this2.app.authManager.registerTypes(_preset.presetAuthType, {
|
|
76
|
+
auth: _basicAuth.BasicAuth
|
|
77
|
+
});
|
|
78
|
+
// Register actions
|
|
79
|
+
Object.entries(_auth.default).forEach(([action, handler]) => _this2.app.resourcer.registerAction(`auth:${action}`, handler));
|
|
80
|
+
Object.entries(_authenticators.default).forEach(([action, handler]) => _this2.app.resourcer.registerAction(`authenticators:${action}`, handler));
|
|
81
|
+
// Set up ACL
|
|
82
|
+
['check', 'signIn', 'signUp'].forEach(action => _this2.app.acl.allow('auth', action));
|
|
83
|
+
['signOut', 'changePassword'].forEach(action => _this2.app.acl.allow('auth', action, 'loggedIn'));
|
|
84
|
+
_this2.app.acl.allow('authenticators', 'publicList');
|
|
85
|
+
_this2.app.acl.registerSnippet({
|
|
86
|
+
name: `pm.${_this2.name}.authenticators`,
|
|
87
|
+
actions: ['authenticators:*']
|
|
88
|
+
});
|
|
89
|
+
})();
|
|
90
|
+
}
|
|
91
|
+
install(options) {
|
|
92
|
+
var _this3 = this;
|
|
93
|
+
return _asyncToGenerator(function* () {
|
|
94
|
+
const repository = _this3.db.getRepository('authenticators');
|
|
95
|
+
const exist = yield repository.findOne({
|
|
96
|
+
filter: {
|
|
97
|
+
name: _preset.presetAuthenticator
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (exist) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
yield repository.create({
|
|
104
|
+
values: {
|
|
105
|
+
name: _preset.presetAuthenticator,
|
|
106
|
+
authType: _preset.presetAuthType,
|
|
107
|
+
description: 'Sign in with email and password.',
|
|
108
|
+
enabled: true,
|
|
109
|
+
options: {
|
|
110
|
+
public: {
|
|
111
|
+
allowSignUp: true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
})();
|
|
117
|
+
}
|
|
118
|
+
afterEnable() {
|
|
119
|
+
return _asyncToGenerator(function* () {})();
|
|
120
|
+
}
|
|
121
|
+
afterDisable() {
|
|
122
|
+
return _asyncToGenerator(function* () {})();
|
|
123
|
+
}
|
|
124
|
+
remove() {
|
|
125
|
+
return _asyncToGenerator(function* () {})();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.AuthPlugin = AuthPlugin;
|
|
129
|
+
var _default = AuthPlugin;
|
|
130
|
+
exports.default = _default;
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nocobase/plugin-auth",
|
|
3
|
+
"version": "0.10.0-alpha.2",
|
|
4
|
+
"main": "lib/server/index.js",
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@nocobase/actions": "0.10.0-alpha.2",
|
|
7
|
+
"@nocobase/client": "0.10.0-alpha.2",
|
|
8
|
+
"@nocobase/database": "0.10.0-alpha.2",
|
|
9
|
+
"@nocobase/server": "0.10.0-alpha.2",
|
|
10
|
+
"@nocobase/test": "0.10.0-alpha.2"
|
|
11
|
+
},
|
|
12
|
+
"displayName": "Authentication",
|
|
13
|
+
"displayName.zh-CN": "用户认证",
|
|
14
|
+
"description": "Basic authentication and authenticator management.",
|
|
15
|
+
"description.zh-CN": "提供基础认证功能和扩展认证器管理功能。",
|
|
16
|
+
"gitHead": "85028ae1733fcbd46ecd5d291dacbdc175f7f073"
|
|
17
|
+
}
|
package/server.d.ts
ADDED
package/server.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
4
|
+
if (typeof WeakMap !== 'function') return null;
|
|
5
|
+
var cacheBabelInterop = new WeakMap();
|
|
6
|
+
var cacheNodeInterop = new WeakMap();
|
|
7
|
+
return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) {
|
|
8
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
9
|
+
})(nodeInterop);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function _interopRequireWildcard(obj, nodeInterop) {
|
|
13
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
|
16
|
+
if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
|
17
|
+
return { default: obj };
|
|
18
|
+
}
|
|
19
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
20
|
+
if (cache && cache.has(obj)) {
|
|
21
|
+
return cache.get(obj);
|
|
22
|
+
}
|
|
23
|
+
var newObj = {};
|
|
24
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
25
|
+
for (var key in obj) {
|
|
26
|
+
if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
27
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
28
|
+
if (desc && (desc.get || desc.set)) {
|
|
29
|
+
Object.defineProperty(newObj, key, desc);
|
|
30
|
+
} else {
|
|
31
|
+
newObj[key] = obj[key];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
newObj.default = obj;
|
|
36
|
+
if (cache) {
|
|
37
|
+
cache.set(obj, newObj);
|
|
38
|
+
}
|
|
39
|
+
return newObj;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
var _index = _interopRequireWildcard(require('./lib/server'));
|
|
43
|
+
|
|
44
|
+
Object.defineProperty(exports, '__esModule', {
|
|
45
|
+
value: true,
|
|
46
|
+
});
|
|
47
|
+
var _exportNames = {};
|
|
48
|
+
Object.defineProperty(exports, 'default', {
|
|
49
|
+
enumerable: true,
|
|
50
|
+
get: function get() {
|
|
51
|
+
return _index.default;
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
Object.keys(_index).forEach(function (key) {
|
|
56
|
+
if (key === 'default' || key === '__esModule') return;
|
|
57
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
58
|
+
if (key in exports && exports[key] === _index[key]) return;
|
|
59
|
+
Object.defineProperty(exports, key, {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function get() {
|
|
62
|
+
return _index[key];
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SchemaComponent } from '@nocobase/client';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useAuthTranslation } from '../locale';
|
|
4
|
+
|
|
5
|
+
export const Options = () => {
|
|
6
|
+
const { t } = useAuthTranslation();
|
|
7
|
+
return (
|
|
8
|
+
<SchemaComponent
|
|
9
|
+
scope={{ t }}
|
|
10
|
+
schema={{
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
public: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
allowSignup: {
|
|
17
|
+
'x-decorator': 'FormItem',
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
title: '{{t("Allow to sign up")}}',
|
|
20
|
+
'x-component': 'Checkbox',
|
|
21
|
+
'x-component-props': {
|
|
22
|
+
defaultChecked: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Authenticator, SchemaComponent, SignupPageContext, useSignIn } from '@nocobase/client';
|
|
2
|
+
import { ISchema } from '@formily/react';
|
|
3
|
+
import React, { useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
const passwordForm: ISchema = {
|
|
6
|
+
type: 'object',
|
|
7
|
+
name: 'passwordForm',
|
|
8
|
+
'x-component': 'FormV2',
|
|
9
|
+
properties: {
|
|
10
|
+
email: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
required: true,
|
|
13
|
+
'x-component': 'Input',
|
|
14
|
+
'x-validator': 'email',
|
|
15
|
+
'x-decorator': 'FormItem',
|
|
16
|
+
'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
|
|
17
|
+
},
|
|
18
|
+
password: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
'x-component': 'Password',
|
|
21
|
+
required: true,
|
|
22
|
+
'x-decorator': 'FormItem',
|
|
23
|
+
'x-component-props': { placeholder: '{{t("Password")}}', style: {} },
|
|
24
|
+
},
|
|
25
|
+
actions: {
|
|
26
|
+
type: 'void',
|
|
27
|
+
'x-component': 'div',
|
|
28
|
+
properties: {
|
|
29
|
+
submit: {
|
|
30
|
+
title: '{{t("Sign in")}}',
|
|
31
|
+
type: 'void',
|
|
32
|
+
'x-component': 'Action',
|
|
33
|
+
'x-component-props': {
|
|
34
|
+
htmlType: 'submit',
|
|
35
|
+
block: true,
|
|
36
|
+
type: 'primary',
|
|
37
|
+
useAction: `{{ useBasicSignIn }}`,
|
|
38
|
+
style: { width: '100%' },
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
signup: {
|
|
44
|
+
type: 'void',
|
|
45
|
+
'x-component': 'Link',
|
|
46
|
+
'x-component-props': {
|
|
47
|
+
to: '{{ signupLink }}',
|
|
48
|
+
},
|
|
49
|
+
'x-content': '{{t("Create an account")}}',
|
|
50
|
+
'x-visible': '{{ allowSignUp }}',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
export default (props: { authenticator: Authenticator }) => {
|
|
55
|
+
const authenticator = props.authenticator;
|
|
56
|
+
const { authType, name, options } = authenticator;
|
|
57
|
+
const signupPages = useContext(SignupPageContext);
|
|
58
|
+
const allowSignUp = !!signupPages[authType] && options?.allowSignup;
|
|
59
|
+
const signupLink = `/signup?authType=${authType}&name=${name}`;
|
|
60
|
+
|
|
61
|
+
const useBasicSignIn = () => {
|
|
62
|
+
return useSignIn(name);
|
|
63
|
+
};
|
|
64
|
+
return <SchemaComponent schema={passwordForm} scope={{ useBasicSignIn, allowSignUp, signupLink }} />;
|
|
65
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { SchemaComponent, useSignup } from '@nocobase/client';
|
|
2
|
+
import { ISchema } from '@formily/react';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { uid } from '@formily/shared';
|
|
5
|
+
|
|
6
|
+
const signupPageSchema: ISchema = {
|
|
7
|
+
type: 'object',
|
|
8
|
+
name: uid(),
|
|
9
|
+
'x-component': 'FormV2',
|
|
10
|
+
properties: {
|
|
11
|
+
email: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
required: true,
|
|
14
|
+
'x-component': 'Input',
|
|
15
|
+
'x-validator': 'email',
|
|
16
|
+
'x-decorator': 'FormItem',
|
|
17
|
+
'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
|
|
18
|
+
},
|
|
19
|
+
password: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
required: true,
|
|
22
|
+
'x-component': 'Password',
|
|
23
|
+
'x-decorator': 'FormItem',
|
|
24
|
+
'x-component-props': { placeholder: '{{t("Password")}}', checkStrength: true, style: {} },
|
|
25
|
+
'x-reactions': [
|
|
26
|
+
{
|
|
27
|
+
dependencies: ['.confirm_password'],
|
|
28
|
+
fulfill: {
|
|
29
|
+
state: {
|
|
30
|
+
selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
confirm_password: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
required: true,
|
|
39
|
+
'x-component': 'Password',
|
|
40
|
+
'x-decorator': 'FormItem',
|
|
41
|
+
'x-component-props': { placeholder: '{{t("Confirm password")}}', style: {} },
|
|
42
|
+
'x-reactions': [
|
|
43
|
+
{
|
|
44
|
+
dependencies: ['.password'],
|
|
45
|
+
fulfill: {
|
|
46
|
+
state: {
|
|
47
|
+
selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
actions: {
|
|
54
|
+
type: 'void',
|
|
55
|
+
'x-component': 'div',
|
|
56
|
+
properties: {
|
|
57
|
+
submit: {
|
|
58
|
+
title: '{{t("Sign up")}}',
|
|
59
|
+
type: 'void',
|
|
60
|
+
'x-component': 'Action',
|
|
61
|
+
'x-component-props': {
|
|
62
|
+
block: true,
|
|
63
|
+
type: 'primary',
|
|
64
|
+
htmlType: 'submit',
|
|
65
|
+
useAction: '{{ useBasicSignup }}',
|
|
66
|
+
style: { width: '100%' },
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
link: {
|
|
72
|
+
type: 'void',
|
|
73
|
+
'x-component': 'div',
|
|
74
|
+
properties: {
|
|
75
|
+
link: {
|
|
76
|
+
type: 'void',
|
|
77
|
+
'x-component': 'Link',
|
|
78
|
+
'x-component-props': { to: '/signin' },
|
|
79
|
+
'x-content': '{{t("Log in with an existing account")}}',
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default (props: { name: string }) => {
|
|
87
|
+
const useBasicSignup = () => {
|
|
88
|
+
return useSignup({ authenticator: props.name });
|
|
89
|
+
};
|
|
90
|
+
return <SchemaComponent schema={signupPageSchema} scope={{ useBasicSignup }} />;
|
|
91
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OptionsComponentProvider,
|
|
3
|
+
SettingsCenterProvider,
|
|
4
|
+
SigninPageProvider,
|
|
5
|
+
SignupPageProvider,
|
|
6
|
+
} from '@nocobase/client';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { Authenticator } from './settings/Authenticator';
|
|
9
|
+
import SigninPage from './basic/SigninPage';
|
|
10
|
+
import { presetAuthType } from '../preset';
|
|
11
|
+
import SignupPage from './basic/SignupPage';
|
|
12
|
+
import { useAuthTranslation } from './locale';
|
|
13
|
+
import { Options } from './basic/Options';
|
|
14
|
+
|
|
15
|
+
export default (props) => {
|
|
16
|
+
const { t } = useAuthTranslation();
|
|
17
|
+
return (
|
|
18
|
+
<SettingsCenterProvider
|
|
19
|
+
settings={{
|
|
20
|
+
auth: {
|
|
21
|
+
title: t('Authentication'),
|
|
22
|
+
icon: 'LoginOutlined',
|
|
23
|
+
tabs: {
|
|
24
|
+
authenticators: {
|
|
25
|
+
title: t('Authenticators'),
|
|
26
|
+
component: () => <Authenticator />,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<OptionsComponentProvider authType={presetAuthType} component={Options}>
|
|
33
|
+
<SigninPageProvider authType={presetAuthType} tabTitle={t('Sign in via email')} component={SigninPage}>
|
|
34
|
+
<SignupPageProvider authType={presetAuthType} component={SignupPage}>
|
|
35
|
+
{props.children}
|
|
36
|
+
</SignupPageProvider>
|
|
37
|
+
</SigninPageProvider>
|
|
38
|
+
</OptionsComponentProvider>
|
|
39
|
+
</SettingsCenterProvider>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ActionContextProvider,
|
|
3
|
+
SchemaComponent,
|
|
4
|
+
useAPIClient,
|
|
5
|
+
useActionContext,
|
|
6
|
+
useAsyncData,
|
|
7
|
+
useRequest,
|
|
8
|
+
} from '@nocobase/client';
|
|
9
|
+
import { Card } from 'antd';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
import { authenticatorsSchema, createFormSchema } from './schemas/authenticators';
|
|
12
|
+
import { Button, Dropdown } from 'antd';
|
|
13
|
+
import { PlusOutlined, DownOutlined } from '@ant-design/icons';
|
|
14
|
+
import { AuthTypeContext, AuthTypesContext, useAuthTypes } from './authType';
|
|
15
|
+
import { useValuesFromOptions, Options } from './Options';
|
|
16
|
+
import { useTranslation } from 'react-i18next';
|
|
17
|
+
|
|
18
|
+
const useCloseAction = () => {
|
|
19
|
+
const { setVisible } = useActionContext();
|
|
20
|
+
return {
|
|
21
|
+
async run() {
|
|
22
|
+
setVisible(false);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const AddNew = () => {
|
|
28
|
+
const { t } = useTranslation();
|
|
29
|
+
const [visible, setVisible] = useState(false);
|
|
30
|
+
const [type, setType] = useState('');
|
|
31
|
+
const types = useAuthTypes();
|
|
32
|
+
const items = types.map((item) => ({
|
|
33
|
+
...item,
|
|
34
|
+
onClick: () => {
|
|
35
|
+
setVisible(true);
|
|
36
|
+
setType(item.value);
|
|
37
|
+
},
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<ActionContextProvider value={{ visible, setVisible }}>
|
|
42
|
+
<AuthTypeContext.Provider value={{ type }}>
|
|
43
|
+
<Dropdown menu={{ items }}>
|
|
44
|
+
<Button icon={<PlusOutlined />} type={'primary'}>
|
|
45
|
+
{t('Add new')} <DownOutlined />
|
|
46
|
+
</Button>
|
|
47
|
+
</Dropdown>
|
|
48
|
+
<SchemaComponent scope={{ useCloseAction, types, setType }} schema={createFormSchema} />
|
|
49
|
+
</AuthTypeContext.Provider>
|
|
50
|
+
</ActionContextProvider>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Disable delete button when there is only one authenticator
|
|
55
|
+
const useCanNotDelete = () => {
|
|
56
|
+
const { data } = useAsyncData();
|
|
57
|
+
// return data?.meta?.count === 1;
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const Authenticator = () => {
|
|
62
|
+
const [types, setTypes] = useState([]);
|
|
63
|
+
const api = useAPIClient();
|
|
64
|
+
useRequest(
|
|
65
|
+
() =>
|
|
66
|
+
api
|
|
67
|
+
.resource('authenticators')
|
|
68
|
+
.listTypes()
|
|
69
|
+
.then((res) => {
|
|
70
|
+
const types = res?.data?.data || [];
|
|
71
|
+
return types.map((type: string) => ({
|
|
72
|
+
key: type,
|
|
73
|
+
label: type,
|
|
74
|
+
value: type,
|
|
75
|
+
}));
|
|
76
|
+
}),
|
|
77
|
+
{
|
|
78
|
+
onSuccess: (types) => {
|
|
79
|
+
setTypes(types);
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<Card bordered={false}>
|
|
86
|
+
<AuthTypesContext.Provider value={{ types }}>
|
|
87
|
+
<SchemaComponent
|
|
88
|
+
schema={authenticatorsSchema}
|
|
89
|
+
components={{ AddNew, Options }}
|
|
90
|
+
scope={{ types, useValuesFromOptions, useCanNotDelete }}
|
|
91
|
+
/>
|
|
92
|
+
</AuthTypesContext.Provider>
|
|
93
|
+
</Card>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRequest, useRecord, useActionContext } from '@nocobase/client';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import { useOptionsComponent } from '@nocobase/client';
|
|
4
|
+
import { observer, useForm } from '@formily/react';
|
|
5
|
+
|
|
6
|
+
export const useValuesFromOptions = (options) => {
|
|
7
|
+
const record = useRecord();
|
|
8
|
+
const result = useRequest(
|
|
9
|
+
() =>
|
|
10
|
+
Promise.resolve({
|
|
11
|
+
data: {
|
|
12
|
+
...record.options,
|
|
13
|
+
},
|
|
14
|
+
}),
|
|
15
|
+
{
|
|
16
|
+
...options,
|
|
17
|
+
manual: true,
|
|
18
|
+
},
|
|
19
|
+
);
|
|
20
|
+
const { run } = result;
|
|
21
|
+
const ctx = useActionContext();
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (ctx.visible) {
|
|
24
|
+
run();
|
|
25
|
+
}
|
|
26
|
+
}, [ctx.visible, run]);
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const Options = observer(() => {
|
|
31
|
+
const form = useForm();
|
|
32
|
+
const record = useRecord();
|
|
33
|
+
const component = useOptionsComponent(form.values.authType || record.authType);
|
|
34
|
+
return component;
|
|
35
|
+
});
|