fix: set acl role
This commit is contained in:
		
							parent
							
								
									b586d370f0
								
							
						
					
					
						commit
						0fd41c9036
					
				@ -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);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										104
									
								
								packages/plugin-users/src/__tests__/setCurrentRole.test.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								packages/plugin-users/src/__tests__/setCurrentRole.test.ts
									
									
									
									
									
										Normal 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');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
@ -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';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ export default {
 | 
			
		||||
  name: 'users',
 | 
			
		||||
  title: '{{t("Users")}}',
 | 
			
		||||
  sortable: 'sort',
 | 
			
		||||
  model: 'UserModel',
 | 
			
		||||
  fields: [
 | 
			
		||||
    {
 | 
			
		||||
      interface: 'input',
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										41
									
								
								packages/plugin-users/src/models/UserModel.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								packages/plugin-users/src/models/UserModel.ts
									
									
									
									
									
										Normal 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -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');
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user