fix: set acl role

This commit is contained in:
chenos 2022-04-10 22:05:18 +08:00
parent b586d370f0
commit 0fd41c9036
7 changed files with 171 additions and 38 deletions

View File

@ -1,4 +1,5 @@
import { useFieldSchema } from '@formily/react';
import { useCookieState } from 'ahooks';
import { Spin } from 'antd';
import React, { createContext, useContext } from 'react';
import { Redirect } from 'react-router-dom';
@ -20,6 +21,7 @@ export const ACLProvider = (props) => {
export const ACLRolesCheckProvider = (props) => {
const { setDesignable } = useDesignable();
const [roleName, setRoleName] = useCookieState('currentRoleName');
const result = useRequest(
{
url: 'roles:check',
@ -29,6 +31,9 @@ export const ACLRolesCheckProvider = (props) => {
if (!data?.data?.allowConfigure && !data?.data?.allowAll) {
setDesignable(false);
}
if (data?.data?.role !== roleName) {
setRoleName(data?.data?.role);
}
},
},
);

View File

@ -0,0 +1,104 @@
import Database from '@nocobase/database';
import PluginACL from '@nocobase/plugin-acl';
import UsersPlugin from '@nocobase/plugin-users';
import { MockServer, mockServer } from '@nocobase/test';
import { setCurrentRole } from '../middlewares/parseToken';
import { userPluginConfig } from './utils';
describe('role', () => {
let api: MockServer;
let db: Database;
let usersPlugin: UsersPlugin;
beforeEach(async () => {
api = mockServer();
await api.cleanDb();
api.plugin(UsersPlugin, userPluginConfig);
api.plugin(PluginACL);
await api.loadAndInstall();
db = api.db;
usersPlugin = api.getPlugin('@nocobase/plugin-users');
});
afterEach(async () => {
await api.destroy();
});
it('should set role with X-Role when exists', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'admin';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('admin');
});
it('should set role with default', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return '';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with default when x-role does not exist', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'abc';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('root');
});
it('should set role with anonymous', async () => {
const currentUser = await db.getRepository('users').findOne({
appends: ['roles'],
});
const ctx = {
get(name) {
if (name === 'X-Role') {
return 'anonymous';
}
},
state: {
currentUser,
currentRole: '',
}
}
setCurrentRole(ctx);
expect(ctx.state.currentRole).toBe('anonymous');
});
});

View File

@ -155,31 +155,7 @@ export async function setDefaultRole(ctx: Context, next: Next) {
values: { roleName },
} = ctx.action.params;
if (roleName == 'anonymous') {
ctx.body = 'ok';
return next();
}
const currentUserId = ctx.state.currentUser.id;
await ctx.db.getRepository('rolesUsers').update({
filter: {
userId: currentUserId,
},
values: {
default: false,
},
});
await ctx.db.getRepository('rolesUsers').update({
filter: {
userId: currentUserId,
roleName,
},
values: {
default: true,
},
});
await ctx.state.currentUser.setDefaultRole(roleName);
ctx.body = 'ok';

View File

@ -4,6 +4,7 @@ export default {
name: 'users',
title: '{{t("Users")}}',
sortable: 'sort',
model: 'UserModel',
fields: [
{
interface: 'input',

View File

@ -6,32 +6,34 @@ export function parseToken(options?: { plugin: UsersPlugin }) {
const user = await findUserByToken(ctx, options.plugin);
if (user) {
ctx.state.currentUser = user;
setCurrentRole(ctx, user);
setCurrentRole(ctx);
}
return next();
};
}
function setCurrentRole(ctx, user) {
const roleName = ctx.get('X-Role');
export function setCurrentRole(ctx) {
let currentRole = ctx.get('X-Role');
if (roleName === 'anonymous') {
ctx.state.currentRole = roleName;
if (currentRole === 'anonymous') {
ctx.state.currentRole = currentRole;
return;
}
const userRoles = user.get('roles');
let userRole;
const userRoles = ctx.state.currentUser.roles;
if (userRoles.length == 1) {
userRole = userRoles[0].get('name');
currentRole = userRoles[0].name;
} else if (userRoles.length > 1) {
const defaultRole = userRoles.findIndex((role) => role.get('rolesUsers').default);
userRole = (defaultRole !== -1 ? userRoles[defaultRole] : userRoles[0]).get('name');
const role = userRoles.find((role) => role.name === currentRole);
if (!role) {
const defaultRole = userRoles.find((role) => role.rolesUsers?.default);
currentRole = (defaultRole || userRoles[0])?.name;
}
}
if (userRole) {
ctx.state.currentRole = userRole;
if (currentRole) {
ctx.state.currentRole = currentRole;
}
}

View File

@ -0,0 +1,41 @@
import Database, { Model, TransactionAble } from '@nocobase/database';
export class UserModel extends Model {
async setDefaultRole(roleName: string, options: TransactionAble = {}) {
if (roleName == 'anonymous') {
return false;
}
const db = (this.constructor as any).database as Database;
const transaction = options.transaction || (await db.sequelize.transaction());
try {
await db.getRepository('rolesUsers').update({
filter: {
userId: this.get('id'),
},
values: {
default: false,
},
transaction,
});
await db.getRepository('rolesUsers').update({
filter: {
userId: this.get('id'),
roleName,
},
values: {
default: true,
},
transaction,
});
await transaction.commit();
} catch (error) {
await transaction.rollback();
throw error;
}
return true;
}
}

View File

@ -4,6 +4,7 @@ import { resolve } from 'path';
import * as actions from './actions/users';
import { JwtOptions, JwtService } from './jwt-service';
import * as middlewares from './middlewares';
import { UserModel } from './models/UserModel';
export interface UserPluginConfig {
jwt: JwtOptions;
@ -24,6 +25,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
}
async beforeLoad() {
this.db.registerModels({ UserModel });
this.db.on('users.afterCreateWithAssociations', async (model, options) => {
const { transaction } = options;
@ -113,7 +115,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
const { adminNickname, adminPassword, adminEmail } = this.getRootUserInfo();
const User = this.db.getCollection('users');
await User.repository.create({
const user = await User.repository.create<UserModel>({
values: {
nickname: adminNickname,
email: adminEmail,
@ -122,6 +124,8 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
},
});
await user.setDefaultRole('root');
const repo = this.db.getRepository<any>('collections');
if (repo) {
await repo.db2cm('users');