feat(users): add users module (#26)
* feat(users): add users module * user check
This commit is contained in:
parent
3da40bd35b
commit
d9e6d2e614
@ -131,14 +131,14 @@ const data = {
|
|||||||
icon: 'dashboard',
|
icon: 'dashboard',
|
||||||
sort: 110,
|
sort: 110,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: '权限配置',
|
// title: '权限配置',
|
||||||
type: 'collection',
|
// type: 'collection',
|
||||||
collection: 'roles',
|
// collection: 'roles',
|
||||||
path: '/settings/roles',
|
// path: '/settings/roles',
|
||||||
icon: 'dashboard',
|
// icon: 'dashboard',
|
||||||
sort: 120,
|
// sort: 120,
|
||||||
},
|
// },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -311,6 +311,31 @@ const data = {
|
|||||||
// return await collection.modelInit();
|
// return await collection.modelInit();
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
|
await Page.create({
|
||||||
|
title: '登录页面',
|
||||||
|
path: '/login',
|
||||||
|
type: 'page',
|
||||||
|
inherit: false,
|
||||||
|
template: 'login',
|
||||||
|
order: 120,
|
||||||
|
});
|
||||||
|
|
||||||
|
await Page.create({
|
||||||
|
title: '注册页面',
|
||||||
|
path: '/register',
|
||||||
|
type: 'page',
|
||||||
|
inherit: false,
|
||||||
|
template: 'register',
|
||||||
|
order: 130,
|
||||||
|
});
|
||||||
|
|
||||||
|
await database.getModel('users').create({
|
||||||
|
nickname: "admin",
|
||||||
|
password: "admin",
|
||||||
|
username: "admin",
|
||||||
|
token: "38979f07e1fca68fb3d2",
|
||||||
|
});
|
||||||
|
|
||||||
api.listen(process.env.HTTP_PORT, () => {
|
api.listen(process.env.HTTP_PORT, () => {
|
||||||
console.log(`http://localhost:${process.env.HTTP_PORT}/`);
|
console.log(`http://localhost:${process.env.HTTP_PORT}/`);
|
||||||
});
|
});
|
||||||
|
@ -21,4 +21,37 @@ export const request: RequestConfig = {
|
|||||||
await next();
|
await next();
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function getInitialState() {
|
||||||
|
const { pathname, search } = location;
|
||||||
|
console.log(location);
|
||||||
|
let redirect = '';
|
||||||
|
// if (href.includes('?')) {
|
||||||
|
redirect = `?redirect=${pathname}${search}`;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (pathname !== '/login' && pathname !== '/register') {
|
||||||
|
try {
|
||||||
|
const { data = {} } = await umiRequest('/users:check', {
|
||||||
|
method: 'post',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data.id) {
|
||||||
|
history.push('/login' + redirect);
|
||||||
|
return {
|
||||||
|
currentUser: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentUser: data,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
history.push('/login' + redirect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
@ -29,9 +29,11 @@ export function Details(props: any) {
|
|||||||
<Actions {...props} style={{ marginBottom: 14 }} actions={actions}/>
|
<Actions {...props} style={{ marginBottom: 14 }} actions={actions}/>
|
||||||
{loading ? <Spin/> : (
|
{loading ? <Spin/> : (
|
||||||
<Descriptions bordered column={1}>
|
<Descriptions bordered column={1}>
|
||||||
{fields.map((field: any) => (
|
{fields.map((field: any) => {
|
||||||
<Descriptions.Item label={field.title||field.name}>{data[field.name]}</Descriptions.Item>
|
return (
|
||||||
))}
|
<Descriptions.Item label={field.title||field.name}>{JSON.stringify(data[field.name])}</Descriptions.Item>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -57,7 +57,8 @@ export const DrawerForm = forwardRef((props: any, ref) => {
|
|||||||
title={title}
|
title={title}
|
||||||
footer={[
|
footer={[
|
||||||
<Button type={'primary'} onClick={async () => {
|
<Button type={'primary'} onClick={async () => {
|
||||||
await actions.submit();
|
const values = await actions.submit();
|
||||||
|
console.log(values);
|
||||||
}}>提交</Button>
|
}}>提交</Button>
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
74
packages/app/src/components/views/Form/Login.tsx
Normal file
74
packages/app/src/components/views/Form/Login.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tooltip, Card, Button } from 'antd';
|
||||||
|
import {
|
||||||
|
SchemaForm,
|
||||||
|
SchemaMarkupField as Field,
|
||||||
|
createFormActions,
|
||||||
|
createAsyncFormActions,
|
||||||
|
Submit,
|
||||||
|
Reset,
|
||||||
|
FormButtonGroup,
|
||||||
|
registerFormFields,
|
||||||
|
FormValidator,
|
||||||
|
setValidationLanguage,
|
||||||
|
} from '@formily/antd';
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Link, history, request, useModel, useLocation } from 'umi';
|
||||||
|
|
||||||
|
export function Login(props: any) {
|
||||||
|
const actions = createAsyncFormActions();
|
||||||
|
const { initialState = {}, loading, error, refresh, setInitialState } = useModel('@@initialState');
|
||||||
|
const { redirect } = props.location.query;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'users-form'}>
|
||||||
|
<h1>NocoBase</h1>
|
||||||
|
<h2>登录</h2>
|
||||||
|
<SchemaForm onSubmit={async (values) => {
|
||||||
|
console.log(values);
|
||||||
|
const { data = {} } = await request('/users:login', {
|
||||||
|
method: 'post',
|
||||||
|
data: values,
|
||||||
|
});
|
||||||
|
if (data.data && data.data.token) {
|
||||||
|
localStorage.setItem('NOCOBASE_TOKEN', data.data.token);
|
||||||
|
setInitialState({currentUser :data.data});
|
||||||
|
await (window as any).routesReload();
|
||||||
|
history.push(redirect||'/');
|
||||||
|
}
|
||||||
|
}} actions={actions} schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
title: '',
|
||||||
|
required: true,
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
placeholder: '用户名',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'password',
|
||||||
|
title: '',
|
||||||
|
required: true,
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
placeholder: '密码',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<FormButtonGroup>
|
||||||
|
<Submit size={'large'}>登录</Submit>
|
||||||
|
<Button size={'large'} onClick={() => {
|
||||||
|
history.push('/register');
|
||||||
|
}}>注册账户</Button>
|
||||||
|
</FormButtonGroup>
|
||||||
|
</SchemaForm>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
125
packages/app/src/components/views/Form/Register.tsx
Normal file
125
packages/app/src/components/views/Form/Register.tsx
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tooltip, Card, Button, message } from 'antd';
|
||||||
|
import {
|
||||||
|
SchemaForm,
|
||||||
|
SchemaMarkupField as Field,
|
||||||
|
createFormActions,
|
||||||
|
createAsyncFormActions,
|
||||||
|
Submit,
|
||||||
|
Reset,
|
||||||
|
FormButtonGroup,
|
||||||
|
registerFormFields,
|
||||||
|
FormEffectHooks,
|
||||||
|
FormValidator,
|
||||||
|
setValidationLanguage,
|
||||||
|
} from '@formily/antd';
|
||||||
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Link, history, request, useModel } from 'umi';
|
||||||
|
|
||||||
|
const { onFieldValueChange$ } = FormEffectHooks
|
||||||
|
|
||||||
|
const useLinkageValidateEffects = () => {
|
||||||
|
const { setFieldState, getFieldState } = createFormActions()
|
||||||
|
onFieldValueChange$('*(password,confirm)').subscribe(fieldState => {
|
||||||
|
const selfName = fieldState.name
|
||||||
|
const selfValue = fieldState.value
|
||||||
|
const otherName = selfName == 'password' ? 'confirm' : 'password'
|
||||||
|
const otherValue = getFieldState(otherName, state => state.value)
|
||||||
|
setFieldState(otherName, state => {
|
||||||
|
if (selfValue && otherValue && selfValue !== otherValue) {
|
||||||
|
state.errors = ['两次密码输入不一致']
|
||||||
|
} else {
|
||||||
|
state.errors = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setFieldState(selfName, state => {
|
||||||
|
if (selfValue && otherValue && selfValue !== otherValue) {
|
||||||
|
state.errors = ['两次密码输入不一致']
|
||||||
|
} else {
|
||||||
|
state.errors = []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Register(props: any) {
|
||||||
|
const actions = createFormActions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={'users-form'}>
|
||||||
|
<h1>NocoBase</h1>
|
||||||
|
<h2>注册</h2>
|
||||||
|
<SchemaForm
|
||||||
|
effects={() => {
|
||||||
|
useLinkageValidateEffects()
|
||||||
|
}}
|
||||||
|
onSubmit={async (values) => {
|
||||||
|
console.log(values);
|
||||||
|
const { data = {} } = await request('/users:register', {
|
||||||
|
method: 'post',
|
||||||
|
data: values,
|
||||||
|
});
|
||||||
|
await actions.reset({
|
||||||
|
validate: false,
|
||||||
|
forceClear: true,
|
||||||
|
});
|
||||||
|
message.success('注册成功,将跳转登录页');
|
||||||
|
setTimeout(() => {
|
||||||
|
history.push('/login');
|
||||||
|
}, 1000);
|
||||||
|
}} actions={actions} schema={{
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
username: {
|
||||||
|
type: 'string',
|
||||||
|
title: '',
|
||||||
|
required: true,
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
placeholder: '用户名',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nickname: {
|
||||||
|
type: 'string',
|
||||||
|
title: '',
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
placeholder: '昵称',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'password',
|
||||||
|
title: '',
|
||||||
|
required: true,
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
placeholder: '密码',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
type: 'password',
|
||||||
|
title: '',
|
||||||
|
required: true,
|
||||||
|
'x-component-props': {
|
||||||
|
size: 'large',
|
||||||
|
style: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
placeholder: '确认密码',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<FormButtonGroup>
|
||||||
|
<Submit size={'large'}>注册</Submit>
|
||||||
|
<Button size={'large'} onClick={() => {
|
||||||
|
history.push('/login');
|
||||||
|
}}>使用已有账号登录</Button>
|
||||||
|
</FormButtonGroup>
|
||||||
|
</SchemaForm>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -12,6 +12,7 @@ import {
|
|||||||
FormValidator,
|
FormValidator,
|
||||||
setValidationLanguage,
|
setValidationLanguage,
|
||||||
} from '@formily/antd';
|
} from '@formily/antd';
|
||||||
|
import './style.less';
|
||||||
|
|
||||||
setup();
|
setup();
|
||||||
setValidationLanguage('zh-CN');
|
setValidationLanguage('zh-CN');
|
||||||
|
5
packages/app/src/components/views/Form/style.less
Normal file
5
packages/app/src/components/views/Form/style.less
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
.users-form {
|
||||||
|
max-width: 368px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-top: 100px;
|
||||||
|
}
|
@ -86,7 +86,7 @@ export function SimpleTable(props: SimpleTableProps) {
|
|||||||
{...tableProps}
|
{...tableProps}
|
||||||
/>
|
/>
|
||||||
{paginated && (
|
{paginated && (
|
||||||
<div>
|
<div className={'table-pagination'}>
|
||||||
<Pagination {...pagination} showQuickJumper showSizeChanger size={'default'}/>
|
<Pagination {...pagination} showQuickJumper showSizeChanger size={'default'}/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -102,7 +102,7 @@ export function Table(props: TableProps) {
|
|||||||
{...tableProps}
|
{...tableProps}
|
||||||
/>
|
/>
|
||||||
{paginated && (
|
{paginated && (
|
||||||
<div>
|
<div className={'table-pagination'}>
|
||||||
<Pagination {...pagination} showQuickJumper showSizeChanger size={'default'}/>
|
<Pagination {...pagination} showQuickJumper showSizeChanger size={'default'}/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -7,6 +7,9 @@ import { SimpleTable } from './SimpleTable';
|
|||||||
import { Table } from './Table';
|
import { Table } from './Table';
|
||||||
import { Form, DrawerForm } from './Form/index';
|
import { Form, DrawerForm } from './Form/index';
|
||||||
import { Details } from './Details';
|
import { Details } from './Details';
|
||||||
|
import './style.less';
|
||||||
|
import { Login } from './Form/Login';
|
||||||
|
import { Register } from './Form/Register';
|
||||||
|
|
||||||
const TEMPLATES = new Map<string, any>();
|
const TEMPLATES = new Map<string, any>();
|
||||||
|
|
||||||
@ -24,6 +27,8 @@ registerView('Form', Form);
|
|||||||
registerView('Table', Table);
|
registerView('Table', Table);
|
||||||
registerView('SimpleTable', SimpleTable);
|
registerView('SimpleTable', SimpleTable);
|
||||||
registerView('Details', Details);
|
registerView('Details', Details);
|
||||||
|
registerView('Login', Login);
|
||||||
|
registerView('Register', Register);
|
||||||
|
|
||||||
export interface ViewProps {
|
export interface ViewProps {
|
||||||
resourceName: string;
|
resourceName: string;
|
||||||
|
13
packages/app/src/components/views/style.less
Normal file
13
packages/app/src/components/views/style.less
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
.ant-table-cell:not(.ant-table-selection-column) {
|
||||||
|
min-width: 100px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.ant-table-wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.table-pagination {
|
||||||
|
margin-top: 24px;
|
||||||
|
ul {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
16
packages/app/src/pages/login.tsx
Normal file
16
packages/app/src/pages/login.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'umi';
|
||||||
|
import { Page } from '@/components/pages';
|
||||||
|
import ViewFactory from '@/components/views';
|
||||||
|
|
||||||
|
export default (props: any) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ViewFactory
|
||||||
|
{...props}
|
||||||
|
viewName={'login'}
|
||||||
|
resourceName={'users'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
16
packages/app/src/pages/register.tsx
Normal file
16
packages/app/src/pages/register.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'umi';
|
||||||
|
import { Page } from '@/components/pages';
|
||||||
|
import ViewFactory from '@/components/views';
|
||||||
|
|
||||||
|
export default (props: any) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ViewFactory
|
||||||
|
{...props}
|
||||||
|
viewName={'register'}
|
||||||
|
resourceName={'users'}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -10,4 +10,6 @@ export default {
|
|||||||
'page2': require('@/pages/page2').default,
|
'page2': require('@/pages/page2').default,
|
||||||
'page3': require('@/pages/page3').default,
|
'page3': require('@/pages/page3').default,
|
||||||
'page4': require('@/pages/page4').default,
|
'page4': require('@/pages/page4').default,
|
||||||
|
login: require('@/pages/login').default,
|
||||||
|
register: require('@/pages/register').default,
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
"umi": "^3.2.23"
|
"umi": "^3.2.23"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@nocobase/actions": "^0.3.0-alpha.0",
|
||||||
|
"crypto-random-string": "^3.3.0",
|
||||||
"umi": "^3.2.23"
|
"umi": "^3.2.23"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
6
packages/plugin-users/src/actions/check.ts
Normal file
6
packages/plugin-users/src/actions/check.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { actions } from '@nocobase/actions';
|
||||||
|
|
||||||
|
export default async (ctx: actions.Context, next: actions.Next) => {
|
||||||
|
ctx.body = ctx.state.currentUser;
|
||||||
|
await next();
|
||||||
|
}
|
28
packages/plugin-users/src/actions/login.ts
Normal file
28
packages/plugin-users/src/actions/login.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { actions } from '@nocobase/actions';
|
||||||
|
import cryptoRandomString from 'crypto-random-string';
|
||||||
|
import { Password } from "@nocobase/database";
|
||||||
|
|
||||||
|
export default async (ctx: actions.Context, next: actions.Next) => {
|
||||||
|
const { values } = ctx.action.params;
|
||||||
|
// console.log(values);
|
||||||
|
const User = ctx.db.getModel('users');
|
||||||
|
const user = await User.findOne({
|
||||||
|
where: {
|
||||||
|
username: values.username,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) {
|
||||||
|
ctx.throw(401, 'Unauthorized');
|
||||||
|
}
|
||||||
|
if (!Password.verify(values.password, user.password)) {
|
||||||
|
ctx.throw(401, 'Unauthorized');
|
||||||
|
}
|
||||||
|
if (!user.token) {
|
||||||
|
user.token = cryptoRandomString({length: 20});
|
||||||
|
await user.save();
|
||||||
|
}
|
||||||
|
ctx.body = {
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
await next();
|
||||||
|
}
|
6
packages/plugin-users/src/actions/logout.ts
Normal file
6
packages/plugin-users/src/actions/logout.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { actions } from '@nocobase/actions';
|
||||||
|
|
||||||
|
export default async (ctx: actions.Context, next: actions.Next) => {
|
||||||
|
ctx.body = {};
|
||||||
|
await next();
|
||||||
|
}
|
11
packages/plugin-users/src/actions/register.ts
Normal file
11
packages/plugin-users/src/actions/register.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { actions } from '@nocobase/actions';
|
||||||
|
|
||||||
|
export default async (ctx: actions.Context, next: actions.Next) => {
|
||||||
|
const User = ctx.db.getModel('users');
|
||||||
|
const { values } = ctx.action.params;
|
||||||
|
const user = await User.create(values);
|
||||||
|
ctx.body = {
|
||||||
|
data: user,
|
||||||
|
};
|
||||||
|
await next();
|
||||||
|
}
|
@ -5,9 +5,64 @@ export default {
|
|||||||
title: '用户',
|
title: '用户',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
|
interface: 'string',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'username',
|
name: 'username',
|
||||||
title: '用户名',
|
title: '用户名',
|
||||||
|
unique: true,
|
||||||
|
component: {
|
||||||
|
type: 'string',
|
||||||
|
showInTable: true,
|
||||||
|
showInDetail: true,
|
||||||
|
showInForm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
interface: 'string',
|
||||||
|
type: 'string',
|
||||||
|
name: 'nickname',
|
||||||
|
title: '昵称',
|
||||||
|
component: {
|
||||||
|
type: 'string',
|
||||||
|
showInTable: true,
|
||||||
|
showInDetail: true,
|
||||||
|
showInForm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
interface: 'phone',
|
||||||
|
type: 'string',
|
||||||
|
name: 'phone',
|
||||||
|
unique: true,
|
||||||
|
title: '手机号',
|
||||||
|
component: {
|
||||||
|
type: 'string',
|
||||||
|
showInTable: true,
|
||||||
|
showInDetail: true,
|
||||||
|
showInForm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
interface: 'password',
|
||||||
|
type: 'password',
|
||||||
|
name: 'password',
|
||||||
|
title: '密码',
|
||||||
|
hidden: true,
|
||||||
|
component: {
|
||||||
|
type: 'password',
|
||||||
|
showInForm: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
interface: 'password',
|
||||||
|
type: 'string',
|
||||||
|
name: 'token',
|
||||||
|
title: 'Token',
|
||||||
|
unique: true,
|
||||||
|
hidden: true,
|
||||||
|
component: {
|
||||||
|
type: 'hidden',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
@ -41,6 +96,18 @@ export default {
|
|||||||
title: '表单',
|
title: '表单',
|
||||||
template: 'DrawerForm',
|
template: 'DrawerForm',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
name: 'login',
|
||||||
|
title: '登录',
|
||||||
|
template: 'Login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'form',
|
||||||
|
name: 'register',
|
||||||
|
title: '注册',
|
||||||
|
template: 'Register',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'details',
|
type: 'details',
|
||||||
name: 'details',
|
name: 'details',
|
||||||
|
32
packages/plugin-users/src/resources/users.ts
Normal file
32
packages/plugin-users/src/resources/users.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { ResourceOptions } from "@nocobase/resourcer";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'users',
|
||||||
|
middlewares: [
|
||||||
|
{
|
||||||
|
// only: ['check'],
|
||||||
|
handler: async (ctx, next) => {
|
||||||
|
const token = ctx.get('Authorization').replace(/^Bearer\s+/gi, '');
|
||||||
|
console.log(ctx.action.params.actionName);
|
||||||
|
const { actionName } = ctx.action.params;
|
||||||
|
if (actionName !== 'check') {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
if (!token) {
|
||||||
|
ctx.throw(401, 'Unauthorized');
|
||||||
|
}
|
||||||
|
const User = ctx.db.getModel('users');
|
||||||
|
const user = await User.findOne({
|
||||||
|
where: {
|
||||||
|
token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!user) {
|
||||||
|
ctx.throw(401, 'Unauthorized');
|
||||||
|
}
|
||||||
|
ctx.state.currentUser = user;
|
||||||
|
await next();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as ResourceOptions;
|
@ -1,6 +1,10 @@
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import Database from '@nocobase/database';
|
import Database from '@nocobase/database';
|
||||||
import Resourcer from '@nocobase/resourcer';
|
import Resourcer from '@nocobase/resourcer';
|
||||||
|
import login from './actions/login';
|
||||||
|
import register from './actions/register';
|
||||||
|
import logout from './actions/logout';
|
||||||
|
import check from './actions/check';
|
||||||
|
|
||||||
export default async function (options = {}) {
|
export default async function (options = {}) {
|
||||||
const database: Database = this.database;
|
const database: Database = this.database;
|
||||||
@ -9,4 +13,15 @@ export default async function (options = {}) {
|
|||||||
database.import({
|
database.import({
|
||||||
directory: path.resolve(__dirname, 'collections'),
|
directory: path.resolve(__dirname, 'collections'),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
resourcer.registerHandlers({
|
||||||
|
'users:login': login,
|
||||||
|
'users:register': register,
|
||||||
|
'users:logout': logout,
|
||||||
|
'users:check': check,
|
||||||
|
});
|
||||||
|
|
||||||
|
resourcer.import({
|
||||||
|
directory: path.resolve(__dirname, 'resources'),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user