fix: set acl role
This commit is contained in:
		
							parent
							
								
									b586d370f0
								
							
						
					
					
						commit
						0fd41c9036
					
				@ -1,4 +1,5 @@
 | 
				
			|||||||
import { useFieldSchema } from '@formily/react';
 | 
					import { useFieldSchema } from '@formily/react';
 | 
				
			||||||
 | 
					import { useCookieState } from 'ahooks';
 | 
				
			||||||
import { Spin } from 'antd';
 | 
					import { Spin } from 'antd';
 | 
				
			||||||
import React, { createContext, useContext } from 'react';
 | 
					import React, { createContext, useContext } from 'react';
 | 
				
			||||||
import { Redirect } from 'react-router-dom';
 | 
					import { Redirect } from 'react-router-dom';
 | 
				
			||||||
@ -20,6 +21,7 @@ export const ACLProvider = (props) => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const ACLRolesCheckProvider = (props) => {
 | 
					export const ACLRolesCheckProvider = (props) => {
 | 
				
			||||||
  const { setDesignable } = useDesignable();
 | 
					  const { setDesignable } = useDesignable();
 | 
				
			||||||
 | 
					  const [roleName, setRoleName] = useCookieState('currentRoleName');
 | 
				
			||||||
  const result = useRequest(
 | 
					  const result = useRequest(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      url: 'roles:check',
 | 
					      url: 'roles:check',
 | 
				
			||||||
@ -29,6 +31,9 @@ export const ACLRolesCheckProvider = (props) => {
 | 
				
			|||||||
        if (!data?.data?.allowConfigure && !data?.data?.allowAll) {
 | 
					        if (!data?.data?.allowConfigure && !data?.data?.allowAll) {
 | 
				
			||||||
          setDesignable(false);
 | 
					          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 },
 | 
					    values: { roleName },
 | 
				
			||||||
  } = ctx.action.params;
 | 
					  } = ctx.action.params;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (roleName == 'anonymous') {
 | 
					  await ctx.state.currentUser.setDefaultRole(roleName);
 | 
				
			||||||
    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,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ctx.body = 'ok';
 | 
					  ctx.body = 'ok';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ export default {
 | 
				
			|||||||
  name: 'users',
 | 
					  name: 'users',
 | 
				
			||||||
  title: '{{t("Users")}}',
 | 
					  title: '{{t("Users")}}',
 | 
				
			||||||
  sortable: 'sort',
 | 
					  sortable: 'sort',
 | 
				
			||||||
 | 
					  model: 'UserModel',
 | 
				
			||||||
  fields: [
 | 
					  fields: [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      interface: 'input',
 | 
					      interface: 'input',
 | 
				
			||||||
 | 
				
			|||||||
@ -6,32 +6,34 @@ export function parseToken(options?: { plugin: UsersPlugin }) {
 | 
				
			|||||||
    const user = await findUserByToken(ctx, options.plugin);
 | 
					    const user = await findUserByToken(ctx, options.plugin);
 | 
				
			||||||
    if (user) {
 | 
					    if (user) {
 | 
				
			||||||
      ctx.state.currentUser = user;
 | 
					      ctx.state.currentUser = user;
 | 
				
			||||||
      setCurrentRole(ctx, user);
 | 
					      setCurrentRole(ctx);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return next();
 | 
					    return next();
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function setCurrentRole(ctx, user) {
 | 
					export function setCurrentRole(ctx) {
 | 
				
			||||||
  const roleName = ctx.get('X-Role');
 | 
					  let currentRole = ctx.get('X-Role');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (roleName === 'anonymous') {
 | 
					  if (currentRole === 'anonymous') {
 | 
				
			||||||
    ctx.state.currentRole = roleName;
 | 
					    ctx.state.currentRole = currentRole;
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const userRoles = user.get('roles');
 | 
					  const userRoles = ctx.state.currentUser.roles;
 | 
				
			||||||
  let userRole;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (userRoles.length == 1) {
 | 
					  if (userRoles.length == 1) {
 | 
				
			||||||
    userRole = userRoles[0].get('name');
 | 
					    currentRole = userRoles[0].name;
 | 
				
			||||||
  } else if (userRoles.length > 1) {
 | 
					  } else if (userRoles.length > 1) {
 | 
				
			||||||
    const defaultRole = userRoles.findIndex((role) => role.get('rolesUsers').default);
 | 
					    const role = userRoles.find((role) => role.name === currentRole);
 | 
				
			||||||
    userRole = (defaultRole !== -1 ? userRoles[defaultRole] : userRoles[0]).get('name');
 | 
					    if (!role) {
 | 
				
			||||||
 | 
					      const defaultRole = userRoles.find((role) => role.rolesUsers?.default);
 | 
				
			||||||
 | 
					      currentRole = (defaultRole || userRoles[0])?.name;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (userRole) {
 | 
					  if (currentRole) {
 | 
				
			||||||
    ctx.state.currentRole = userRole;
 | 
					    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 * as actions from './actions/users';
 | 
				
			||||||
import { JwtOptions, JwtService } from './jwt-service';
 | 
					import { JwtOptions, JwtService } from './jwt-service';
 | 
				
			||||||
import * as middlewares from './middlewares';
 | 
					import * as middlewares from './middlewares';
 | 
				
			||||||
 | 
					import { UserModel } from './models/UserModel';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface UserPluginConfig {
 | 
					export interface UserPluginConfig {
 | 
				
			||||||
  jwt: JwtOptions;
 | 
					  jwt: JwtOptions;
 | 
				
			||||||
@ -24,6 +25,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async beforeLoad() {
 | 
					  async beforeLoad() {
 | 
				
			||||||
 | 
					    this.db.registerModels({ UserModel });
 | 
				
			||||||
    this.db.on('users.afterCreateWithAssociations', async (model, options) => {
 | 
					    this.db.on('users.afterCreateWithAssociations', async (model, options) => {
 | 
				
			||||||
      const { transaction } = options;
 | 
					      const { transaction } = options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -113,7 +115,7 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
 | 
				
			|||||||
    const { adminNickname, adminPassword, adminEmail } = this.getRootUserInfo();
 | 
					    const { adminNickname, adminPassword, adminEmail } = this.getRootUserInfo();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const User = this.db.getCollection('users');
 | 
					    const User = this.db.getCollection('users');
 | 
				
			||||||
    await User.repository.create({
 | 
					    const user = await User.repository.create<UserModel>({
 | 
				
			||||||
      values: {
 | 
					      values: {
 | 
				
			||||||
        nickname: adminNickname,
 | 
					        nickname: adminNickname,
 | 
				
			||||||
        email: adminEmail,
 | 
					        email: adminEmail,
 | 
				
			||||||
@ -122,6 +124,8 @@ export default class UsersPlugin extends Plugin<UserPluginConfig> {
 | 
				
			|||||||
      },
 | 
					      },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await user.setDefaultRole('root');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const repo = this.db.getRepository<any>('collections');
 | 
					    const repo = this.db.getRepository<any>('collections');
 | 
				
			||||||
    if (repo) {
 | 
					    if (repo) {
 | 
				
			||||||
      await repo.db2cm('users');
 | 
					      await repo.db2cm('users');
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user