When binding roles, the user list is changed to the drop-down selection mode (在绑定角色的时候用户列表改成下拉选中的模式) #3518 (#3522)

* 配置pageSize列表 #3439

* Service List Page Increase the number of pages switching function is the same as the configuration management page #3500

* issues#3500 编译之后的代码

* 在绑定角色的时候用户列表改成下拉选中的模式 #3518

* change code style

* delete unused import

* delete changed indent please.

* Javadoc add an ending period

* fix bad sql and change return type

* change js get value

* delete whitespace

* check code style

* add permissions, associated role, change to fuzzy matching drop-down(java code)

* add permissions, associated role, change to fuzzy matching drop-down(js code)

* delete "/"
This commit is contained in:
ZZQ的 2020-08-06 13:23:53 +08:00 committed by GitHub
parent a64a356e45
commit 7a471c5100
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 146 additions and 13 deletions

View File

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.ROLE_INFO_ROW_MAPPER;
@ -134,4 +135,11 @@ public class EmbeddedRolePersistServiceImpl implements RolePersistService {
}
}
@Override
public List<String> findRolesLikeRoleName(String role) {
String sql = "SELECT role FROM roles WHERE role like ? ";
List<String> users = databaseOperate.queryMany(sql, new String[] {"%" + role + "%"}, String.class);
return users;
}
}

View File

@ -28,6 +28,7 @@ import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.USER_ROW_MAPPER;
@ -117,4 +118,11 @@ public class EmbeddedUserPersistServiceImpl implements UserPersistService {
}
return pageInfo;
}
@Override
public List<String> findUserLikeUsername(String username) {
String sql = "SELECT username FROM users WHERE username like ? ";
List<String> users = databaseOperate.queryMany(sql, new String[] {"%" + username + "%"}, String.class);
return users;
}
}

View File

@ -33,6 +33,7 @@ import javax.annotation.PostConstruct;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.ROLE_INFO_ROW_MAPPER;
@ -152,6 +153,13 @@ public class ExternalRolePersistServiceImpl implements RolePersistService {
}
}
@Override
public List<String> findRolesLikeRoleName(String role) {
String sql = "SELECT role FROM roles WHERE role like '%' ? '%'";
List<String> users = this.jt.queryForList(sql, new String[]{role}, String.class);
return users;
}
private static final class RoleInfoRowMapper implements RowMapper<RoleInfo> {
@Override

View File

@ -31,6 +31,7 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import static com.alibaba.nacos.config.server.service.repository.RowMapperManager.USER_ROW_MAPPER;
@ -145,4 +146,11 @@ public class ExternalUserPersistServiceImpl implements UserPersistService {
throw e;
}
}
@Override
public List<String> findUserLikeUsername(String username) {
String sql = "SELECT username FROM users WHERE username like '%' ? '%'";
List<String> users = this.jt.queryForList(sql, new String[]{username}, String.class);
return users;
}
}

View File

@ -18,6 +18,8 @@ package com.alibaba.nacos.config.server.auth;
import com.alibaba.nacos.config.server.model.Page;
import java.util.List;
/**
* Role CRUD service.
*
@ -37,4 +39,5 @@ public interface RolePersistService {
void deleteRole(String role, String username);
List<String> findRolesLikeRoleName(String role);
}

View File

@ -19,6 +19,8 @@ package com.alibaba.nacos.config.server.auth;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.User;
import java.util.List;
/**
* User CRUD service.
*
@ -37,5 +39,7 @@ public interface UserPersistService {
User findUserByUsername(String username);
Page<User> getUsers(int pageNo, int pageSize);
List<String> findUserLikeUsername(String username);
}

View File

@ -30,6 +30,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Role operation controller.
*
@ -58,6 +60,18 @@ public class RoleController {
return roleService.getRolesFromDatabase(username, pageNo, pageSize);
}
/**
* Fuzzy matching role name .
*
* @param role role id
* @return role list
*/
@GetMapping("/search")
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "roles", action = ActionTypes.READ)
public List<String> searchRoles(@RequestParam String role) {
return roleService.findRolesLikeRoleName(role);
}
/**
* Add a role to a user
*

View File

@ -248,4 +248,17 @@ public class UserController {
}
return rr;
}
/**
* Fuzzy matching username.
*
* @param username username
* @return Matched username
*/
@GetMapping("/search")
@Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
public List<String> searchUsersLikeUsername(@RequestParam String username) {
return userDetailsService.findUserLikeUsername(username);
}
}

View File

@ -235,4 +235,8 @@ public class NacosRoleServiceImpl {
public void deletePermission(String role, String resource, String action) {
permissionPersistService.deletePermission(role, resource, action);
}
public List<String> findRolesLikeRoleName(String role) {
return rolePersistService.findRolesLikeRoleName(role);
}
}

View File

@ -28,6 +28,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -99,7 +100,11 @@ public class NacosUserDetailsServiceImpl implements UserDetailsService {
public User getUserFromDatabase(String username) {
return userPersistService.findUserByUsername(username);
}
public List<String> findUserLikeUsername(String username) {
return userPersistService.findUserLikeUsername(username);
}
public void createUser(String username, String password) {
userPersistService.createUser(username, password);
}

View File

@ -19,6 +19,7 @@ import PropTypes from 'prop-types';
import { Field, Form, Input, Select, Dialog, ConfigProvider } from '@alifd/next';
import { connect } from 'react-redux';
import { getNamespaces } from '../../../reducers/namespace';
import { searchRoles } from '../../../reducers/authority';
const FormItem = Form.Item;
const { Option } = Select;
@ -28,7 +29,7 @@ const formItemLayout = {
wrapperCol: { span: 19 },
};
@connect(state => ({ namespaces: state.namespace.namespaces }), { getNamespaces })
@connect(state => ({ namespaces: state.namespace.namespaces }), { getNamespaces, searchRoles })
@ConfigProvider.config
class NewPermissions extends React.Component {
static displayName = 'NewPermissions';
@ -39,11 +40,15 @@ class NewPermissions extends React.Component {
locale: PropTypes.object,
visible: PropTypes.bool,
getNamespaces: PropTypes.func,
getRoles: PropTypes.func,
onOk: PropTypes.func,
onCancel: PropTypes.func,
namespaces: PropTypes.array,
};
state = {
dataSource: [],
};
componentDidMount() {
this.props.getNamespaces();
}
@ -68,6 +73,14 @@ class NewPermissions extends React.Component {
return null;
}
handleChange = value => {
if (value.length > 0) {
searchRoles(value).then(val => {
this.setState({ dataSource: val });
});
}
};
render() {
const { getError } = this.field;
const { visible, onOk, onCancel, locale, namespaces } = this.props;
@ -88,7 +101,14 @@ class NewPermissions extends React.Component {
>
<Form style={{ width: 400 }} {...formItemLayout} field={this.field}>
<FormItem label={locale.role} required help={getError('role')}>
<Input name="role" trim placeholder={locale.rolePlaceholder} />
<Select.AutoComplete
name="role"
style={{ width: 316 }}
filterLocal={false}
placeholder={locale.rolePlaceholder}
onChange={this.handleChange}
dataSource={this.state.dataSource}
/>
</FormItem>
<FormItem label={locale.resource} required help={getError('resource')}>
<Select

View File

@ -16,7 +16,9 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Field, Form, Input, Dialog, ConfigProvider } from '@alifd/next';
import { connect } from 'react-redux';
import { Field, Form, Input, Dialog, ConfigProvider, Select } from '@alifd/next';
import { searchUsers } from '../../../reducers/authority';
const FormItem = Form.Item;
@ -24,7 +26,7 @@ const formItemLayout = {
labelCol: { fixedSpan: 4 },
wrapperCol: { span: 19 },
};
@connect(state => ({ users: state.authority.users }), { searchUsers })
@ConfigProvider.config
class NewRole extends React.Component {
static displayName = 'NewRole';
@ -35,9 +37,14 @@ class NewRole extends React.Component {
locale: PropTypes.object,
visible: PropTypes.bool,
onOk: PropTypes.func,
getUsers: PropTypes.func,
onCancel: PropTypes.func,
};
state = {
dataSource: [],
};
check() {
const { locale } = this.props;
const errors = {
@ -57,6 +64,14 @@ class NewRole extends React.Component {
return null;
}
handleChange = value => {
if (value.length > 0) {
searchUsers(value).then(val => {
this.setState({ dataSource: val });
});
}
};
render() {
const { locale } = this.props;
const { getError } = this.field;
@ -81,7 +96,14 @@ class NewRole extends React.Component {
<Input name="role" trim placeholder={locale.rolePlaceholder} />
</FormItem>
<FormItem label={locale.username} required help={getError('username')}>
<Input name="username" placeholder={locale.usernamePlaceholder} />
<Select.AutoComplete
name="username"
style={{ width: 316 }}
filterLocal={false}
placeholder={locale.usernamePlaceholder}
onChange={this.handleChange}
dataSource={this.state.dataSource}
/>
</FormItem>
</Form>
</Dialog>

View File

@ -60,6 +60,13 @@ const getUsers = params => dispatch =>
const createUser = ([username, password]) =>
request.post('v1/auth/users', { username, password }).then(res => successMsg(res));
/**
* 通过username 模糊匹配
* @param {*} param0
*/
const searchUsers = username =>
request.get('v1/auth/users/search', { params: { username } }).then(res => successMsg(res));
/**
* 删除用户
* @param {*} username
@ -82,6 +89,13 @@ const passwordReset = ([username, newPassword]) =>
const getRoles = params => dispatch =>
request.get('v1/auth/roles', { params }).then(data => dispatch({ type: ROLE_LIST, data }));
/**
* 通过username 模糊匹配
* @param {*} param0
*/
const searchRoles = role =>
request.get('v1/auth/roles/search', { params: { role } }).then(res => successMsg(res));
/**
* 创建角色
* @param {*} param0
@ -133,10 +147,12 @@ export default (state = initialState, action) => {
};
export {
searchUsers,
getUsers,
createUser,
deleteUser,
passwordReset,
searchRoles,
getRoles,
createRole,
deleteRole,

File diff suppressed because one or more lines are too long