迁移 system 服务,admin 逻辑

This commit is contained in:
YunaiV 2020-05-01 11:04:16 +08:00
parent 2543d95d0e
commit 157b166435
48 changed files with 627 additions and 400 deletions

View File

@ -4,17 +4,19 @@ import {
addAdmin,
adminRoleAssign,
deleteAdmin,
queryAdmin,
queryAdminRoleList,
updateAdmin,
updateAdminStatus,
deptTreeAll,
} from '../../services/admin';
import {
adminPage
} from '../../services/system';
import { arrayToStringParams } from '../../utils/request.qs';
import PaginationHelper from '../../../helpers/PaginationHelper';
const SEARCH_PARAMS_DEFAULT = {
nickname: '',
name: '',
};
const buildSelectTree = list => {
@ -76,7 +78,7 @@ export default {
});
// 请求
const response = yield call(queryAdmin, payload);
const response = yield call(adminPage, payload);
// 响应
yield put({
type: 'setAll',
@ -84,7 +86,7 @@ export default {
list: response.data.list,
pagination: PaginationHelper.formatPagination(response.data, payload),
searchParams: {
nickname: payload.nickname || '',
name: payload.name || '',
},
},
});

View File

@ -28,7 +28,7 @@ import PaginationHelper from '../../../helpers/PaginationHelper';
const FormItem = Form.Item;
const { TreeNode } = Tree;
const status = ['未知', '正常', '禁用'];
const status = ['未知', '在职', '离职'];
// 列表
function List({
@ -52,23 +52,6 @@ function List({
});
}
function handleStatus(record) {
Modal.confirm({
title: record.status === 1 ? '确认禁用' : '取消禁用',
content: `${record.username}`,
onOk() {
dispatch({
type: 'adminList/updateStatus',
payload: {
id: record.id,
status: record.status === 1 ? 2 : 1,
},
});
},
onCancel() {},
});
}
function handleDelete(record) {
Modal.confirm({
title: `确认删除?`,
@ -92,7 +75,7 @@ function List({
},
{
title: '员工姓名',
dataIndex: 'nickname',
dataIndex: 'name',
},
{
title: '部门',
@ -115,7 +98,7 @@ function List({
},
},
{
title: '状态',
title: '在职状态',
dataIndex: 'status',
render(val) {
return <span>{status[val]}</span>; // TODO 芋艿此处要改
@ -130,16 +113,12 @@ function List({
title: '操作',
width: 360,
render: (text, record) => {
const statusText = record.status === 1 ? '禁用' : '开启'; // TODO 芋艿此处要改
return (
<Fragment>
<a onClick={() => handleModalVisible(true, 'update', record)}>编辑</a>
<Divider type="vertical" />
<a onClick={() => handleRoleAssign(record)}>角色分配</a>
<Divider type="vertical" />
<a className={styles.tableDelete} onClick={() => handleStatus(record)}>
{statusText}
</a>
{record.status === 2 ? (
<span>
<Divider type="vertical" />
@ -223,7 +202,7 @@ const SearchForm = Form.create()(props => {
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={6} sm={24}>
<FormItem label="员工姓名">
{getFieldDecorator('nickname')(<Input style={{ width: 250 }} placeholder="请输入" />)}
{getFieldDecorator('name')(<Input style={{ width: 200 }} placeholder="请输入" />)}
</FormItem>
</Col>
<Col md={6} sm={24}>
@ -233,7 +212,7 @@ const SearchForm = Form.create()(props => {
})(
<TreeSelect
showSearch
style={{ width: 250 }}
style={{ width: 200 }}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={deptSelectTree}
placeholder="选择部门"
@ -327,26 +306,13 @@ const AddOrUpdateForm = Form.create()(props => {
okText="保存"
onCancel={() => handleModalVisible()}
>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="账号">
{form.getFieldDecorator('username', {
rules: [
{ required: true, message: '请输入账号' },
{ max: 16, min: 6, message: '长度为 6-16 ' },
{
validator: (rule, value, callback) =>
checkTypeWithEnglishAndNumbers(rule, value, callback, '数字以及字母'),
},
],
initialValue: formVals.username,
})(<Input placeholder="请输入" />)}
</FormItem>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="员工姓名">
{form.getFieldDecorator('nickname', {
{form.getFieldDecorator('name', {
rules: [
{ required: true, message: '请输入员工姓名' },
{ max: 10, message: '姓名最大长度为 10' },
],
initialValue: formVals.nickname,
initialValue: formVals.name,
})(<Input placeholder="请输入" />)}
</FormItem>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="归属部门">
@ -364,6 +330,19 @@ const AddOrUpdateForm = Form.create()(props => {
/>
)}
</FormItem>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="账号">
{form.getFieldDecorator('username', {
rules: [
{ required: true, message: '请输入账号' },
{ max: 16, min: 6, message: '长度为 6-16 ' },
{
validator: (rule, value, callback) =>
checkTypeWithEnglishAndNumbers(rule, value, callback, '数字以及字母'),
},
],
initialValue: formVals.username,
})(<Input placeholder="请输入" />)}
</FormItem>
<FormItem labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label="密码">
{form.getFieldDecorator('password', {
rules: [

View File

@ -10,6 +10,7 @@ import styles from './RoleList.less';
const FormItem = Form.Item;
const { TreeNode } = Tree;
const types = ['未知', '系统角色', '自定义角色'];
// 添加 form 表单
const CreateForm = Form.create()(props => {
@ -296,6 +297,13 @@ class RoleList extends PureComponent {
title: '编码',
dataIndex: 'code',
},
{
title: '类型',
dataIndex: 'type',
render(val) {
return <span>{types[val]}</span>;
},
},
{
title: '创建时间',
dataIndex: 'createTime',
@ -307,13 +315,21 @@ class RoleList extends PureComponent {
width: 200,
render: (text, record) => (
<Fragment>
<a onClick={() => this.handleModalVisible(true, 'update', record)}>更新</a>
{record.type === 2 ? (
<span>
<a onClick={() => this.handleModalVisible(true, 'update', record)}>更新</a>
</span>
) : null}
<Divider type="vertical" />
<a onClick={() => this.handleAssignModalVisible(true, record)}>分配权限</a>
<Divider type="vertical" />
<a className={styles.tableDelete} onClick={() => this.handleDelete(record)}>
删除
</a>
{record.type === 2 ? (
<span>
<a className={styles.tableDelete} onClick={() => this.handleDelete(record)}>
删除
</a>
</span>
) : null}
</Fragment>
),
},

View File

@ -89,3 +89,11 @@ export async function roleUpdate(params) {
body: {},
});
}
// ========== Admin 模块 ==========
export async function adminPage(params) {
return request(`/system-api/admins/admin/page?${stringify(params)}`, {
method: 'GET',
});
}

View File

@ -41,6 +41,12 @@ public class CollectionUtil {
Collectors.mapping(valueFunc, Collectors.toList())));
}
// 暂时没想好名字先以 2 结尾噶
public static <T, K, V> Map<K, Set<V>> convertMultiMap2(List<T> from, Function<T, K> keyFunc, Function<T, V> valueFunc) {
return from.stream().collect(Collectors.groupingBy(keyFunc,
Collectors.mapping(valueFunc, Collectors.toSet())));
}
public static boolean containsAny(Collection<?> source, Collection<?> candidates) {
return CollectionUtils.containsAny(source, candidates);
}

View File

@ -16,8 +16,8 @@
<modules>
<module>system-application</module>
<!-- <module>system-sdk</module>-->
<module>system-service-api</module>
<module>system-service-impl</module>
<!-- <module>system-service-api</module>-->
<!-- <module>system-service-impl</module>-->
<module>system-rpc-api</module>
<module>system-rpc</module>
<module>system-rest</module>

View File

@ -16,6 +16,9 @@ public enum SystemErrorCodeEnum implements ServiceExceptionUtil.Enumerable {
OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED(1001001002, "访问令牌已过期"),
OAUTH2_ACCESS_TOKEN_INVALID(1001001003, "访问令牌已失效"),
OAUTH2_NOT_AUTHENTICATE(1001001004, "账号未登陆"),
OAUTH2_REFRESH_TOKEN_NOT_FOUND(1001001005, "刷新令牌不存在"),
OAUTH_REFRESH_TOKEN_EXPIRED(1001001006, "访问令牌已过期"),
OAUTH_REFRESH_TOKEN_INVALID(1001001007, "刷新令牌已失效"),
// 其它 1001001100 开始
OAUTH2_ACCOUNT_NOT_FOUND(1001001100, "账号不存在"),
OAUTH2_ACCOUNT_PASSWORD_ERROR(1001001101, "密码不正确"),
@ -52,6 +55,8 @@ public enum SystemErrorCodeEnum implements ServiceExceptionUtil.Enumerable {
ROLE_NOT_EXISTS(1002004000, "角色不存在"),
ROLE_NAME_DUPLICATE(1002004001, "已经存在名为【{}}】的角色"),
ROLE_CODE_DUPLICATE(1002004002, "已经存在编码为【{}}】的角色"),
ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE(1002004004, "不能修改类型为系统内置的角色"),
ROLE_CAN_NOT_DELETE_SYSTEM_TYPE_ROLE(1002004005, "不能删除类型为系统内置的角色"),
// ========== 数据字典模块 1002005000 ==========
// DATA_DICT_EXISTS(1002005000, "该数据字典已经存在"),

View File

@ -0,0 +1,41 @@
package cn.iocoder.mall.system.biz.enums.admin;
import cn.iocoder.common.framework.core.IntArrayValuable;
import java.util.Arrays;
public enum AdminStatusEnum implements IntArrayValuable {
ACTIVE(1, "在职"),
INACTIVE(2, "离职");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AdminStatusEnum::getStatus).toArray();
/**
* 在职状态
*/
private final Integer status;
/**
* 描述
*/
private final String name;
AdminStatusEnum(Integer status, String name) {
this.status = status;
this.name = name;
}
public Integer getStatus() {
return status;
}
public String getName() {
return name;
}
@Override
public int[] array() {
return ARRAYS;
}
}

View File

@ -1,7 +1,13 @@
package cn.iocoder.mall.system.biz.enums.authorization;
/**
* Resource 编号枚举
*/
public enum ResourceIdEnum {
/**
* 根节点
*/
ROOT(0);
private final Integer id;

View File

@ -5,7 +5,7 @@ import cn.iocoder.common.framework.core.IntArrayValuable;
import java.util.Arrays;
/**
* 资源类型枚举
* Resource 类型枚举
*/
public enum ResourceTypeEnum implements IntArrayValuable {

View File

@ -3,6 +3,8 @@ package cn.iocoder.mall.system.biz.bo.admin;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 管理员模块 - 账号信息 BO
*/
@ -14,9 +16,25 @@ public class AdminBO {
* 管理员编号
*/
private Integer id;
/**
* 账号编号
*/
private Integer accountId;
/**
* 真实名字
*/
private String name;
/**
* 部门编号
*/
private Integer departmentId;
/**
* 在职状态
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -24,6 +24,10 @@ public class RoleBO {
* 角色编码
*/
private String code;
/**
* 角色类型
*/
private Integer type;
/**
* 添加时间
*/

View File

@ -1,8 +1,11 @@
package cn.iocoder.mall.system.biz.convert.admin;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.dataobject.admin.AdminDO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
@ -12,4 +15,7 @@ public interface AdminConvert {
AdminBO convert(AdminDO bean);
@Mapping(source = "records", target = "list")
PageResult<AdminBO> convertPage(IPage<AdminDO> bean);
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.mall.system.biz.convert.oauth2;
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AuthenticateBO;
import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2AccessTokenDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
@ -10,6 +11,7 @@ public interface OAuth2Convert {
OAuth2Convert INSTANCE = Mappers.getMapper(OAuth2Convert.class);
@Mapping(source = "id", target = "accessToken")
OAuth2AuthenticateBO convert(OAuth2AccessTokenDO bean);
}

View File

@ -1,8 +1,12 @@
package cn.iocoder.mall.system.biz.dao.admin;
import cn.iocoder.mall.mybatis.query.QueryWrapperX;
import cn.iocoder.mall.system.biz.dataobject.admin.AdminDO;
import cn.iocoder.mall.system.biz.dto.admin.AdminPageDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
@Repository
@ -14,4 +18,10 @@ public interface AdminMapper extends BaseMapper<AdminDO> {
);
}
default IPage<AdminDO> selectPage(AdminPageDTO adminPageDTO) {
return selectPage(new Page<>(adminPageDTO.getPageNo(), adminPageDTO.getPageSize()),
new QueryWrapperX<AdminDO>().likeIfPresent("name", adminPageDTO.getName())
.eqIfPresent("department_id", adminPageDTO.getDepartmentId()));
}
}

View File

@ -3,26 +3,26 @@ package cn.iocoder.mall.system.biz.dao.authorization;
import cn.iocoder.mall.mybatis.query.QueryWrapperX;
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleDO;
import cn.iocoder.mall.system.biz.dto.authorization.RolePageDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.List;
@Repository
public interface RoleMapper extends BaseMapper<RoleDO> {
default List<RoleDO> selectList() {
return selectList(new QueryWrapper<>());
}
default IPage<RoleDO> selectPage(RolePageDTO rolePageDTO) {
return selectPage(new Page<>(rolePageDTO.getPageNo(), rolePageDTO.getPageSize()),
new QueryWrapperX<RoleDO>().likeIfPresent("name", rolePageDTO.getName()));
}
default List<RoleDO> selectListByIds(Collection<Integer> ids) {
return selectList(new QueryWrapperX<RoleDO>().inIfPresent("id", ids));
}
default RoleDO selectByName(String name) {
return selectOne(new QueryWrapperX<RoleDO>().eqIfPresent("name", name));
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.mall.system.biz.dataobject.admin;
import cn.iocoder.mall.mybatis.dataobject.DeletableDO;
import cn.iocoder.mall.system.biz.dataobject.account.AccountDO;
import cn.iocoder.mall.system.biz.enums.admin.AdminStatusEnum;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -31,10 +32,16 @@ public class AdminDO extends DeletableDO {
*/
private String name;
/**
* 科室编号
* 部门编号
*
* 关联 {@link DepartmentDO#getId()}
*/
private Integer departmentId;
/**
* 在职状态
*
* 枚举 {@link AdminStatusEnum}
*/
private Integer status;
}

View File

@ -0,0 +1,26 @@
package cn.iocoder.mall.system.biz.dto.admin;
import cn.iocoder.common.framework.vo.PageParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 管理员模块 - 管理员分页 DTO
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class AdminPageDTO extends PageParam {
/**
* 真实名字模糊匹配
*/
private String name;
/**
* 部门编号
*/
private Integer departmentId;
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.mall.system.biz.dto.authorization;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.Collection;
/**
* 授权模块 - 获得每个账号所拥有的角色 DTO
*/
@Data
@Accessors(chain = true)
public class AuthorizationGetRoleMapByAccountIdsDTO {
@NotNull(message = "账号编号数组不能为空")
private Collection<Integer> accountIds;
}

View File

@ -14,6 +14,8 @@ public class ResourceGetListDTO {
/**
* 资源编号数组
*
* 如果传入空则不进行资源编号的过滤
*/
private Collection<Integer> ids;

View File

@ -0,0 +1,22 @@
package cn.iocoder.mall.system.biz.dto.authorization;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Collection;
/**
* 角色模块 - 获得角色列表 DTO
*/
@Data
@Accessors(chain = true)
public class RoleGetListDTO {
/**
* 角色编号数组
*
* 如果传入空则不进行角色编号的过滤
*/
private Collection<Integer> ids;
}

View File

@ -3,16 +3,18 @@ package cn.iocoder.mall.system.biz.dto.oatuh2;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.NotEmpty;
// TODO 注释
/**
* 认证模块 - 访问令牌认证 DTO
*/
@Data
@Accessors(chain = true)
public class OAuth2AccessTokenAuthenticateDTO {
@NotNull(message = "访问令牌不能为空")
@NotEmpty(message = "访问令牌不能为空")
private String accessToken;
@NotNull(message = "IP 不能为空")
@NotEmpty(message = "IP 不能为空")
private String ip;
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.mall.system.biz.dto.oatuh2;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
/**
* 认证模块 - 访问令牌认证 DTO
*/
@Data
@Accessors(chain = true)
public class OAuth2RefreshTokenAuthenticateDTO {
@NotEmpty(message = "访问令牌不能为空")
private String refreshToken;
@NotEmpty(message = "IP 不能为空")
private String ip;
}

View File

@ -3,12 +3,19 @@ package cn.iocoder.mall.system.biz.dto.oatuh2;
import lombok.Data;
import lombok.experimental.Accessors;
// TODO 注释
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* 认证模块 - 账号 + 密码认证 DTO
*/
@Data
@Accessors(chain = true)
public class OAuth2UsernameAuthenticateDTO {
@NotEmpty(message = "账号不能为空")
private String username;
@NotNull(message = "密码不能为空")
private String password;
}

View File

@ -1,14 +1,30 @@
package cn.iocoder.mall.system.biz.service.admin;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.dto.admin.AdminPageDTO;
/**
* 管理员 Service 接口
* 管理员模块 - Service 接口
*/
public interface AdminService {
/**
* 根据编号获得管理员信息
*
* @param id 编号
* @return 管理员
*/
AdminBO getAdmin(Integer id);
/**
* 获得账号编号获得管理员信息
*
* @param accountId 账号编号
* @return 管理员
*/
AdminBO getAdminByAccountId(Integer accountId);
PageResult<AdminBO> getAdminPage(AdminPageDTO pageDTO);
}

View File

@ -1,9 +1,10 @@
package cn.iocoder.mall.system.biz.service.admin;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.convert.admin.AdminConvert;
import cn.iocoder.mall.system.biz.dao.admin.AdminMapper;
import cn.iocoder.mall.system.biz.dataobject.admin.AdminDO;
import cn.iocoder.mall.system.biz.dto.admin.AdminPageDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -15,14 +16,17 @@ public class AdminServiceImpl implements AdminService {
@Override
public AdminBO getAdmin(Integer id) {
AdminDO adminDO = adminMapper.selectById(id);
return AdminConvert.INSTANCE.convert(adminDO);
return AdminConvert.INSTANCE.convert(adminMapper.selectById(id));
}
@Override
public AdminBO getAdminByAccountId(Integer accountId) {
AdminDO adminDO = adminMapper.selectByAccountId(accountId);
return AdminConvert.INSTANCE.convert(adminDO);
return AdminConvert.INSTANCE.convert(adminMapper.selectByAccountId(accountId));
}
@Override
public PageResult<AdminBO> getAdminPage(AdminPageDTO pageDTO) {
return AdminConvert.INSTANCE.convertPage(adminMapper.selectPage(pageDTO));
}
}

View File

@ -3,12 +3,11 @@ package cn.iocoder.mall.system.biz.service.authorization;
import cn.iocoder.common.framework.exception.ServiceException;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationAssignRoleResourceDTO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationCheckPermissionsDTO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetResourcesByAccountIdDTO;
import cn.iocoder.mall.system.biz.dto.authorization.AuthorizationGetRoleResourcesDTO;
import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.dto.authorization.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -33,6 +32,14 @@ public interface AuthorizationService {
*/
List<ResourceBO> getResourcesByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO);
/**
* 获得每个账号拥有的角色集合
*
* @param getRoleMapByAccountIdsDTO 查询条件 DTO
* @return <账号编号, <RoleBO>>
*/
Map<Integer, Set<RoleBO>> getRoleMapByAccountIds(AuthorizationGetRoleMapByAccountIdsDTO getRoleMapByAccountIdsDTO);
/**
* 获得指定账号的资源树
*

View File

@ -5,6 +5,7 @@ import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.mall.mybatis.enums.DeletedStatusEnum;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.dao.authorization.AccountRoleMapper;
import cn.iocoder.mall.system.biz.dao.authorization.RoleResourceMapper;
import cn.iocoder.mall.system.biz.dataobject.authorization.AccountRoleDO;
@ -94,6 +95,25 @@ public class AuthorizationServiceImpl implements AuthorizationService {
return resourceService.getResources(new ResourceGetListDTO().setIds(resourceIds).setType(getResourcesByAccountIdDTO.getType()));
}
@Override
public Map<Integer, Set<RoleBO>> getRoleMapByAccountIds(AuthorizationGetRoleMapByAccountIdsDTO getRoleMapByAccountIdsDTO) {
return null;
}
// @Override
// public Map<Integer, Set<RoleBO>> getRoleIdMapByAccountIds(AuthorizationGetRoleMapByAccountIdsDTO getRoleMapByAccountIdsDTO) {
// // 查询管理员拥有的角色关联数据
// List<AccountRoleDO> accountRoleDOs = accountRoleMapper.selectListByAccountIds(getRoleMapByAccountIdsDTO.getAccountIds());
// if (CollectionUtil.isEmpty(accountRoleDOs)) {
// return Collections.emptyMap();
// }
// // 构建结果
// Map<Integer, Set<Integer>> accountRoleMap = CollectionUtil.convertMultiMap2(accountRoleDOs,
// AccountRoleDO::getAccountId, AccountRoleDO::getRoleId);
// getRoleMapByAccountIdsDTO.getAccountIds().forEach(accountId -> accountRoleMap.putIfAbsent(accountId, Collections.emptySet()));
// return accountRoleMap;
// }
@Override
public List<ResourceTreeNodeBO> getResourceTreeByAccountId(AuthorizationGetResourcesByAccountIdDTO getResourcesByAccountIdDTO) {
// 查询管理员拥有的角色关联数据

View File

@ -6,6 +6,7 @@ import cn.iocoder.mall.system.biz.dto.authorization.RoleAddDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleDeleteDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RolePageDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleUpdateDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleGetListDTO;
import java.util.Collection;
import java.util.List;
@ -17,7 +18,7 @@ public interface RoleService {
RoleBO getRole(Integer id);
List<RoleBO> getRoleList(Collection<Integer> ids);
List<RoleBO> getRoleList(RoleGetListDTO getListDTO);
PageResult<RoleBO> getRolePage(RolePageDTO pageDTO);

View File

@ -8,12 +8,10 @@ import cn.iocoder.mall.system.biz.bo.authorization.RoleBO;
import cn.iocoder.mall.system.biz.convert.authorization.RoleConvert;
import cn.iocoder.mall.system.biz.dao.authorization.RoleMapper;
import cn.iocoder.mall.system.biz.dataobject.authorization.RoleDO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleAddDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleDeleteDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RolePageDTO;
import cn.iocoder.mall.system.biz.dto.authorization.RoleUpdateDTO;
import cn.iocoder.mall.system.biz.dto.authorization.*;
import cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum;
import cn.iocoder.mall.system.biz.enums.authorization.RoleCodeEnum;
import cn.iocoder.mall.system.biz.enums.authorization.RoleTypeEnum;
import cn.iocoder.mall.system.biz.event.authorization.ResourceDeleteEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
@ -39,8 +37,8 @@ public class RoleServiceImpl implements RoleService {
}
@Override
public List<RoleBO> getRoleList(Collection<Integer> ids) {
return RoleConvert.INSTANCE.convertList(roleMapper.selectBatchIds(ids));
public List<RoleBO> getRoleList(RoleGetListDTO getListDTO) {
return RoleConvert.INSTANCE.convertList(roleMapper.selectListByIds(getListDTO.getIds()));
}
@Override
@ -62,9 +60,10 @@ public class RoleServiceImpl implements RoleService {
@Override
public Integer addRole(RoleAddDTO roleAddDTO) {
// 校验角色
checkRole(roleAddDTO.getName(), roleAddDTO.getCode(), null);
checkDuplicateRole(roleAddDTO.getName(), roleAddDTO.getCode(), null);
// 保存到数据库
RoleDO role = RoleConvert.INSTANCE.convert(roleAddDTO);
role.setType(RoleTypeEnum.CUSTOM.getType());
role.setCreateTime(new Date());
role.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
roleMapper.insert(role);
@ -76,14 +75,19 @@ public class RoleServiceImpl implements RoleService {
@Override
public void updateRole(RoleUpdateDTO roleUpdateDTO) {
// 校验角色是否存在
if (roleMapper.selectById(roleUpdateDTO.getId()) == null) {
RoleDO roleDO = roleMapper.selectById(roleUpdateDTO.getId());
if (roleDO == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NOT_EXISTS);
}
// 校验角色
checkRole(roleUpdateDTO.getName(), roleUpdateDTO.getCode(), roleUpdateDTO.getId());
// 内置角色不允许修改
if (RoleTypeEnum.SYSTEM.getType().equals(roleDO.getType())) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CAN_NOT_UPDATE_SYSTEM_TYPE_ROLE);
}
// 校验角色的唯一字段是否重复
checkDuplicateRole(roleUpdateDTO.getName(), roleUpdateDTO.getCode(), roleUpdateDTO.getId());
// 更新到数据库
RoleDO roleDO = RoleConvert.INSTANCE.convert(roleUpdateDTO);
roleMapper.updateById(roleDO);
RoleDO updateRole = RoleConvert.INSTANCE.convert(roleUpdateDTO);
roleMapper.updateById(updateRole);
// TODO 插入操作日志
}
@ -91,9 +95,14 @@ public class RoleServiceImpl implements RoleService {
@Transactional
public void deleteRole(RoleDeleteDTO roleDeleteDTO) {
// 校验角色是否存在
if (roleMapper.selectById(roleDeleteDTO.getId()) == null) {
RoleDO roleDO = roleMapper.selectById(roleDeleteDTO.getId());
if (roleDO == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NOT_EXISTS);
}
// 内置角色不允许删除
if (RoleTypeEnum.SYSTEM.getType().equals(roleDO.getType())) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CAN_NOT_DELETE_SYSTEM_TYPE_ROLE);
}
// 更新到数据库标记删除
roleMapper.deleteById(roleDeleteDTO.getId());
// 发布角色删除事件方便清理关联表
@ -102,7 +111,7 @@ public class RoleServiceImpl implements RoleService {
}
/**
* 校验角色是否合法
* 校验角色的唯一字段是否重复
*
* 1. 是否存在相同名字的角色
* 2. 是否存在相同编码的角色
@ -111,31 +120,20 @@ public class RoleServiceImpl implements RoleService {
* @param code 角色额编码
* @param id 角色编号
*/
private void checkRole(String name, String code, Integer id) {
// 1. 是否存在相同名字的角色
private void checkDuplicateRole(String name, String code, Integer id) {
// 1. name 名字被其它角色所使用
RoleDO role = roleMapper.selectByName(name);
if (role != null) {
// 如果 id 为空说明不用比较是否为相同 id 的资源
if (id == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NAME_DUPLICATE, name);
}
if (!role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NAME_DUPLICATE, name);
}
if (role != null && !role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_NAME_DUPLICATE, name);
}
// 2. 是否存在相同编码的角色
if (!StringUtil.hasText(code)) {
return;
}
// code 编码被其它角色所使用
role = roleMapper.selectByCode(code);
if (role != null) {
// 如果 id 为空说明不用比较是否为相同 id 的资源
if (id == null) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CODE_DUPLICATE, name);
}
if (!role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CODE_DUPLICATE, name);
}
if (role != null && !role.getId().equals(id)) {
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.ROLE_CODE_DUPLICATE, name);
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.mall.system.biz.service.oauth2;
import cn.iocoder.mall.system.biz.bo.ouath2.OAuth2AuthenticateBO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2AccessTokenAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2RefreshTokenAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
/**
@ -16,4 +17,6 @@ public interface OAuth2Service {
OAuth2AuthenticateBO authenticate(OAuth2AccessTokenAuthenticateDTO authenticateDTO);
OAuth2AuthenticateBO authenticate(OAuth2RefreshTokenAuthenticateDTO authenticateDTO);
}

View File

@ -13,8 +13,8 @@ import cn.iocoder.mall.system.biz.dataobject.oauth2.OAuth2RefreshTokenDO;
import cn.iocoder.mall.system.biz.dto.account.AccountCreateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2AccessTokenAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2RefreshTokenAuthenticateDTO;
import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2UsernameAuthenticateDTO;
import cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum;
import cn.iocoder.mall.system.biz.service.account.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -24,8 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.UUID;
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.OAUTH2_ACCOUNT_NOT_FOUND;
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.OAUTH2_ACCOUNT_PASSWORD_ERROR;
import static cn.iocoder.mall.system.biz.enums.SystemErrorCodeEnum.*;
@Service
public class OAuth2ServiceImpl implements OAuth2Service {
@ -101,18 +100,42 @@ public class OAuth2ServiceImpl implements OAuth2Service {
public OAuth2AuthenticateBO authenticate(OAuth2AccessTokenAuthenticateDTO authenticateDTO) {
OAuth2AccessTokenDO oauth2AccessTokenDO = oauth2AccessTokenMapper.selectById(authenticateDTO.getAccessToken());
if (oauth2AccessTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_NOT_FOUND.getCode());
throw ServiceExceptionUtil.exception(OAUTH2_ACCESS_TOKEN_NOT_FOUND);
}
if (oauth2AccessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED.getCode());
throw ServiceExceptionUtil.exception(OAUTH2_ACCESS_TOKEN_TOKEN_EXPIRED);
}
if (!oauth2AccessTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(SystemErrorCodeEnum.OAUTH2_ACCESS_TOKEN_INVALID.getCode());
throw ServiceExceptionUtil.exception(OAUTH2_ACCESS_TOKEN_INVALID);
}
// 转换返回
return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);
}
@Override
@Transactional
public OAuth2AuthenticateBO authenticate(OAuth2RefreshTokenAuthenticateDTO authenticateDTO) {
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectById(authenticateDTO.getRefreshToken());
// 校验刷新令牌是否合法
if (refreshTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(OAUTH2_REFRESH_TOKEN_NOT_FOUND);
}
if (refreshTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(OAUTH_REFRESH_TOKEN_EXPIRED);
}
if (!refreshTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(OAUTH_REFRESH_TOKEN_INVALID);
}
// 标记 refreshToken 对应的 accessToken 都不合法
// 这块的实现参考了 Spring Security OAuth2 的代码
oauth2AccessTokenMapper.updateToInvalidByRefreshToken(authenticateDTO.getRefreshToken());
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(refreshTokenDO.getAccountId(),
refreshTokenDO.getId());
// 转换返回
return OAuth2Convert.INSTANCE.convert(oauth2AccessTokenDO);
}
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer accountId, String refreshToken) {
OAuth2AccessTokenDO accessToken = new OAuth2AccessTokenDO()
.setId(generateAccessToken())

View File

@ -1,7 +1,19 @@
package cn.iocoder.mall.system.rest.controller.admin;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.security.core.annotation.RequiresPermissions;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.dto.admin.AdminPageDTO;
import cn.iocoder.mall.system.biz.service.admin.AdminService;
import cn.iocoder.mall.system.rest.convert.admin.AdminsAdminConvert;
import cn.iocoder.mall.system.rest.request.admin.AdminsAdminPageRequest;
import cn.iocoder.mall.system.rest.response.admin.AdminsAdminPageResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -10,6 +22,88 @@ import org.springframework.web.bind.annotation.RestController;
@Api(tags = "管理员 - 管理员 API")
public class AdminsAdminController {
@Autowired
private AdminService adminService;
@GetMapping("/page")
@RequiresPermissions("system:admin:page")
@ApiOperation(value = "管理员分页")
public CommonResult<PageResult<AdminsAdminPageResponse>> page(AdminsAdminPageRequest request) {
// 查询管理员分页
AdminPageDTO pageDTO = AdminsAdminConvert.INSTANCE.convert(request);
PageResult<AdminBO> adminPageBO = adminService.getAdminPage(pageDTO);
PageResult<AdminsAdminPageResponse> adminPageResponse = AdminsAdminConvert.INSTANCE.convertPage(adminPageBO);
if (adminPageResponse.getList().isEmpty()) {
return CommonResult.success(adminPageResponse);
}
// 拼接角色数据
// TODO 拼接部门数据
// 拼接结果
// if (!resultPage.getList().isEmpty()) {
// // 查询角色数组
// Map<Integer, Collection<RoleBO>> roleMap = adminService.getAdminRolesMap(CollectionUtil.convertList(resultPage.getList(), AdminBO::getId));
// resultPage.getList().forEach(admin -> admin.setRoles(AdminConvert.INSTANCE.convertAdminVORoleList(roleMap.get(admin.getId()))));
//
// // 查询对应部门
// List<DeptmentBO> deptmentBOS = deptmentService.getAllDeptments();
// Map<Integer, String> deptNameMap = deptmentBOS.stream().collect(Collectors.toMap(d->d.getId(), d->d.getName()));
// //管理员所在部门被删后变成未分配状态
// deptNameMap.put(0, "未分配");
// resultPage.getList().forEach(admin->{
// admin.setDeptment(new AdminVO.Deptment(admin.getDeptmentId(), deptNameMap.get(admin.getDeptmentId())));
// });
// }
return CommonResult.success(adminPageResponse);
}
// @PostMapping("/add")
// @ApiOperation(value = "创建管理员")
// public CommonResult<AdminBO> add(AdminAddDTO adminAddDTO) {
// return success(adminService.addAdmin(AdminSecurityContextHolder.getContext().getAdminId(), adminAddDTO));
// }
//
// @PostMapping("/update")
// @ApiOperation(value = "更新管理员")
// public CommonResult<Boolean> update(AdminUpdateDTO adminUpdateDTO) {
// return success(adminService.updateAdmin(AdminSecurityContextHolder.getContext().getAdminId(), adminUpdateDTO));
// }
//
// @PostMapping("/update_status")
// @ApiOperation(value = "更新管理员状态")
// public CommonResult<Boolean> updateStatus(AdminUpdateStatusDTO adminUpdateStatusDTO) {
// return success(adminService.updateAdminStatus(AdminSecurityContextHolder.getContext().getAdminId(), adminUpdateStatusDTO));
// }
//
// @PostMapping("/delete")
// @ApiOperation(value = "删除管理员")
// @ApiImplicitParam(name = "id", value = "管理员编号", required = true, example = "1")
// public CommonResult<Boolean> delete(@RequestParam("id") Integer id) {
// return success(adminService.deleteAdmin(AdminSecurityContextHolder.getContext().getAdminId(), id));
// }
//
// @GetMapping("/role_list")
// @ApiOperation(value = "指定管理员拥有的角色列表")
// @ApiImplicitParam(name = "id", value = "管理员编号", required = true, example = "1")
// public CommonResult<List<AdminRoleVO>> roleList(@RequestParam("id") Integer id) {
// // 获得所有角色列表
// List<RoleBO> allRoleList = roleService.getRoleList();
// // 获得管理员的角色数组
// Set<Integer> adminRoleIdSet = CollectionUtil.convertSet(adminService.getRoleList(id), RoleBO::getId);
// // 转换出返回结果
// List<AdminRoleVO> result = AdminConvert.INSTANCE.convert(allRoleList);
// // 设置每个角色是否赋予给改管理员
// result.forEach(adminRoleVO -> adminRoleVO.setAssigned(adminRoleIdSet.contains(adminRoleVO.getId())));
// return success(result);
// }
//
// @PostMapping("/assign_role")
// @ApiOperation(value = "分配给管理员角色")
// public CommonResult<Boolean> assignRole(AdminAssignRoleDTO adminAssignRoleDTO) {
// return success(adminService.assignAdminRole(AdminSecurityContextHolder.getContext().getAdminId(), adminAssignRoleDTO));
// }
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.mall.system.rest.controller.authorization;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.security.core.annotation.RequiresPermissions;
import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceBO;
import cn.iocoder.mall.system.biz.bo.authorization.ResourceTreeNodeBO;
@ -12,6 +13,7 @@ import cn.iocoder.mall.system.biz.dto.authorization.ResourceGetTreeDTO;
import cn.iocoder.mall.system.biz.enums.authorization.ResourceTypeEnum;
import cn.iocoder.mall.system.biz.service.authorization.AuthorizationService;
import cn.iocoder.mall.system.biz.service.authorization.ResourceService;
import cn.iocoder.mall.system.biz.service.authorization.RoleService;
import cn.iocoder.mall.system.rest.convert.authorization.AdminsAuthorizationConvert;
import cn.iocoder.mall.system.rest.request.authorization.AdminsAuthorizationAssignRoleResourceRequest;
import cn.iocoder.mall.system.rest.response.authorization.AdminsAuthorizationMenuTreeResponse;
@ -37,6 +39,8 @@ public class AdminsAuthorizationController {
private AuthorizationService authorizationService;
@Autowired
private ResourceService resourceService;
@Autowired
private RoleService roleService;
@GetMapping("/menu-resource-tree")
@ApiOperation(value = "获得当前账号的菜单资源树", notes = "以树结构返回")
@ -57,6 +61,7 @@ public class AdminsAuthorizationController {
@GetMapping("/role_resource_tree")
@ApiOperation(value = "获得角色拥有的菜单权限", notes = "以树结构返回。注意,返回的资源树是完整的结构,会标记每个资源节点是否被角色所拥有")
@ApiImplicitParam(name = "roleId", value = "角色编号", required = true, example = "1")
@RequiresPermissions("system:authorization:assign_role_resource")
public CommonResult<List<AdminsAuthorizationRoleResourceTreeResponse>> roleResourceTree(@RequestParam("roleId") Integer roleId) {
// 1. 获得完整的资源树
List<ResourceTreeNodeBO> resourceTreeNodeBOs = resourceService.getResourceTree(new ResourceGetTreeDTO());
@ -68,6 +73,7 @@ public class AdminsAuthorizationController {
@PostMapping("/assign_role_resource")
@ApiOperation(value = "分配角色资源")
@RequiresPermissions("system:authorization:assign_role_resource")
public CommonResult<Boolean> assignRoleResource(AdminsAuthorizationAssignRoleResourceRequest request) {
AuthorizationAssignRoleResourceDTO authorizationAssignRoleResourceDTO = AdminsAuthorizationConvert.INSTANCE.convert(request)
.setAdminId(AdminSecurityContextHolder.getAdminId());
@ -75,4 +81,26 @@ public class AdminsAuthorizationController {
return CommonResult.success(true);
}
// @GetMapping("/role_list")
// @ApiOperation(value = "指定账号拥有的角色列表")
// @ApiImplicitParam(name = "accountId", value = "账号编号", required = true, example = "1")
// public CommonResult<List<AdminRoleVO>> roleList(@RequestParam("accountId") Integer accountId) {
// // 获得所有角色列表
// List<RoleBO> allRoleList = roleService.getRoleList();
// // 获得管理员的角色数组
// Set<Integer> adminRoleIdSet = CollectionUtil.convertSet(adminService.getRoleList(id), RoleBO::getId);
// // 转换出返回结果
// List<AdminRoleVO> result = AdminConvert.INSTANCE.convert(allRoleList);
// // 设置每个角色是否赋予给改管理员
// result.forEach(adminRoleVO -> adminRoleVO.setAssigned(adminRoleIdSet.contains(adminRoleVO.getId())));
// return success(result);
// }
//
// @PostMapping("/assign_role")
// @ApiOperation(value = "分配给管理员角色")
// public CommonResult<Boolean> assignRole(AdminAssignRoleDTO adminAssignRoleDTO) {
// return success(adminService.assignAdminRole(AdminSecurityContextHolder.getContext().getAdminId(), adminAssignRoleDTO));
// }
}

View File

@ -1,7 +1,12 @@
package cn.iocoder.mall.system.rest.convert.admin;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.biz.bo.account.AccountUsernameAuthorizeBO;
import cn.iocoder.mall.system.biz.bo.admin.AdminBO;
import cn.iocoder.mall.system.biz.dto.admin.AdminPageDTO;
import cn.iocoder.mall.system.rest.request.admin.AdminsAdminPageRequest;
import cn.iocoder.mall.system.rest.request.oauth2.AdminsOAuth2UsernameAuthenticateRequest;
import cn.iocoder.mall.system.rest.response.admin.AdminsAdminPageResponse;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -12,4 +17,8 @@ public interface AdminsAdminConvert {
AccountUsernameAuthorizeBO convert(AdminsOAuth2UsernameAuthenticateRequest bean);
AdminPageDTO convert(AdminsAdminPageRequest bean);
PageResult<AdminsAdminPageResponse> convertPage(PageResult<AdminBO> bean);
}

View File

@ -17,7 +17,7 @@ public interface AdminsOAuth2Convert {
OAuth2UsernameAuthenticateDTO convert(AdminsOAuth2UsernameAuthenticateRequest bean);
@Mapping(source = "adminBO", target = "admin")
@Mapping(source = "accessTokenBO.id", target = "token.accessToken")
@Mapping(source = "accessTokenBO.accessToken", target = "token.accessToken")
@Mapping(source = "accessTokenBO.refreshToken", target = "token.refreshToken")
@Mapping(source = "accessTokenBO.expiresTime", target = "token.expiresTime")
AdminsOAuth2AuthenticateResponse convert(AdminBO adminBO, OAuth2AuthenticateBO accessTokenBO);

View File

@ -5,7 +5,6 @@ import cn.iocoder.mall.system.biz.dto.oatuh2.OAuth2MobileCodeAuthenticateDTO;
import cn.iocoder.mall.system.rest.request.oauth2.UsersOAuth2MobileCodeAuthenticateRequest;
import cn.iocoder.mall.system.rest.response.user.UsersOAuth2AuthenticateResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
@ -15,7 +14,6 @@ public interface UsersOAuth2Convert {
OAuth2MobileCodeAuthenticateDTO convert(UsersOAuth2MobileCodeAuthenticateRequest bean);
@Mapping(source = "token.id", target = "token.accessToken")
UsersOAuth2AuthenticateResponse convert(UserAuthenticateBO bean);
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.mall.system.rest.request.admin;
import cn.iocoder.common.framework.vo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@ApiModel("管理员 - 管理员模块 - 管理员分页信息 Request")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class AdminsAdminPageRequest extends PageParam {
@ApiModelProperty(value = "真实名字,模糊匹配", example = "小王")
private String name;
@ApiModelProperty(value = "部门编号")
private Integer departmentId;
}

View File

@ -0,0 +1,79 @@
package cn.iocoder.mall.system.rest.response.admin;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
@ApiModel("管理员 - 管理员模块 - 管理员分页信息 Response")
@Data
@Accessors(chain = true)
public class AdminsAdminPageResponse {
@ApiModel("角色")
@Data
@Accessors(chain = true)
public static class Role {
@ApiModelProperty(value = "角色编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "角色名", required = true, example = "码神")
private String name;
}
@ApiModel("部门")
@Data
@Accessors(chain = true)
public static class Department {
@ApiModelProperty(value = "部门编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "部门名称", required = true, example = "研发部")
private String name;
}
@ApiModel("账号")
@Data
@Accessors(chain = true)
public static class Account {
@ApiModelProperty(value = "账号编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "登陆账号", required = true, example = "15601691300")
private String username;
}
@ApiModelProperty(value = "管理员编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "真实名字", required = true, example = "小王")
private String name;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
private Date createTime;
@ApiModelProperty(value = "在职状态", required = true, example = "1", notes = "见 AdminStatusEnum 枚举")
private Integer status;
/**
* 账号
*/
private Account account;
/**
* 角色列表
*/
private List<Role> roles;
/**
* 所在部门
*/
private Department department;
}

View File

@ -18,6 +18,8 @@ public class AdminsRolePageResponse {
private String name;
@ApiModelProperty(value = "角色编码", example = "SUPER_ADMIN")
private String code;
@ApiModelProperty(value = "角色类型", required = true, example = "1-系统角色; 2-内置角色")
private Integer type;
@ApiModelProperty(value = "创建时间", required = true)
private Date createTime;

View File

@ -1,11 +1,8 @@
package cn.iocoder.mall.system.api;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.api.bo.admin.AdminAuthenticationBO;
import cn.iocoder.mall.system.api.bo.admin.AdminAuthorizationBO;
import cn.iocoder.mall.system.api.bo.admin.AdminBO;
import cn.iocoder.mall.system.api.bo.role.RoleBO;
import cn.iocoder.mall.admin.api.dto.admin.*;
import cn.iocoder.mall.system.api.dto.admin.*;
import java.util.Collection;
@ -17,16 +14,6 @@ import java.util.Map;
*/
public interface AdminService {
/**
* 管理员认证认证成功后返回认证信息
*
* 实际上就是用户名 + 密码登陆
*
* @param adminAuthenticationDTO 用户认证信息
* @return 认证信息
*/
AdminAuthenticationBO authentication(AdminAuthenticationDTO adminAuthenticationDTO);
PageResult<AdminBO> getAdminPage(AdminPageDTO adminPageDTO);
AdminBO addAdmin(Integer adminId, AdminAddDTO adminAddDTO);
@ -62,13 +49,4 @@ public interface AdminService {
*/
Boolean assignAdminRole(Integer adminId, AdminAssignRoleDTO adminAssignRoleDTO);
/**
* 判断管理员是否有指定权限
*
* @param adminId 管理员
* @param permissions 权限数组
* @return 管理员授权信息
*/
AdminAuthorizationBO checkPermissions(Integer adminId, List<String> permissions);
}

View File

@ -1,10 +1,5 @@
package cn.iocoder.mall.system.api;
import cn.iocoder.mall.system.api.bo.oauth2.OAuth2AccessTokenBO;
import cn.iocoder.mall.system.api.bo.oauth2.OAuth2AuthenticationBO;
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2CreateTokenDTO;
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2GetTokenDTO;
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2RefreshTokenDTO;
import cn.iocoder.mall.system.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
/**
@ -12,14 +7,6 @@ import cn.iocoder.mall.system.api.dto.oauth2.OAuth2RemoveTokenByUserDTO;
*/
public interface OAuth2Service {
/**
* 根据身份信息创建 accessToken 信息
*
* @param oauth2CreateTokenDTO 身份信息 DTO
* @return accessToken 信息
*/
OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO);
/**
* 基于用户移除 accessToken
*
@ -27,20 +14,4 @@ public interface OAuth2Service {
*/
void removeToken(OAuth2RemoveTokenByUserDTO oauth2RemoveTokenDTO);
/**
* 刷新令牌获得新的 accessToken 信息
*
* @param oauth2RefreshTokenDTO refreshToken 信息
* @return accessToken 信息
*/
OAuth2AccessTokenBO refreshToken(OAuth2RefreshTokenDTO oauth2RefreshTokenDTO);
/**
* 通过 accessToken 获得身份信息
*
* @param oauth2GetTokenDTO accessToken 信息
* @return 身份信息
*/
OAuth2AuthenticationBO getAuthentication(OAuth2GetTokenDTO oauth2GetTokenDTO);
}

View File

@ -1,24 +1,14 @@
package cn.iocoder.mall.system.api;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.system.api.bo.role.RoleBO;
import cn.iocoder.mall.system.api.dto.role.RoleAddDTO;
import cn.iocoder.mall.system.api.dto.role.RoleAssignResourceDTO;
import cn.iocoder.mall.system.api.dto.role.RolePageDTO;
import cn.iocoder.mall.system.api.dto.role.RoleUpdateDTO;
import java.util.Collection;
import java.util.List;
public interface RoleService {
PageResult<RoleBO> getRolePage(RolePageDTO rolePageDTO);
/**
* @return 返回角色列表
*/
List<RoleBO> getRoleList();
Boolean assignRoleResource(Integer adminId, RoleAssignResourceDTO roleAssignResourceDTO);
}

View File

@ -1,28 +0,0 @@
package cn.iocoder.mall.system.api.dto.admin;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@ApiModel("管理员认证 DTO")
@Data
@Accessors(chain = true)
public class AdminAuthenticationDTO {
@ApiModelProperty(value = "登陆账号", required = true, example = "15601691300")
@NotEmpty(message = "登陆账号不能为空")
@Length(min = 5, max = 16, message = "账号长度为 5-16 位")
@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
private String username;
@ApiModelProperty(value = "密码", required = true, example = "buzhidao")
@NotEmpty(message = "密码不能为空")
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
private String password;
}

View File

@ -1,32 +0,0 @@
package cn.iocoder.mall.admin.dao;
import cn.iocoder.common.framework.mybatis.QueryWrapperX;
import cn.iocoder.mall.system.api.dto.admin.AdminPageDTO;
import cn.iocoder.mall.admin.dataobject.AdminDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@Repository
public interface AdminMapper extends BaseMapper<AdminDO> {
default AdminDO selectByUsername(@Param("username") String username) {
return selectOne(new QueryWrapper<AdminDO>().eq("username", username));
}
default IPage<AdminDO> selectPage(AdminPageDTO adminPageDTO) {
return selectPage(new Page<>(adminPageDTO.getPageNo(), adminPageDTO.getPageSize()),
new QueryWrapperX<AdminDO>().likeIfPresent("nickname", adminPageDTO.getNickname())
.eqIfPresent("deptment_id", adminPageDTO.getDeptmentId()));
}
default int updateDeptByDeptId(@Param("fromDeptId")Integer fromDeptId, @Param("toDeptId")Integer toDeptId){
QueryWrapper<AdminDO> query = new QueryWrapper<AdminDO>()
.eq("deptment_id", fromDeptId);
return update(new AdminDO().setDeptmentId(toDeptId), query);
}
}

View File

@ -1,50 +0,0 @@
package cn.iocoder.mall.admin.dataobject;
import cn.iocoder.common.framework.dataobject.DeletableDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 管理员实体
*/
@TableName(value = "admin")
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class AdminDO extends DeletableDO {
/**
* 管理员编号
*/
private Integer id;
/**
* 登陆账号
*/
private String username;
/**
* 昵称
*/
private String nickname;
/**
* 密码
*
* TODO 芋艿 暂时最简单的 MD5
*/
private String password;
/**
* 账号状态
*/
private Integer status;
/**
* 管理员部门id
*/
private Integer deptmentId;
// TODO 芋艿最后登陆时间最后登陆 IP
// TODO 芋艿登陆日志
}

View File

@ -39,27 +39,6 @@ public class OAuth2ServiceImpl implements OAuth2Service {
@Autowired
private AdminServiceImpl adminService;
@Autowired
private OAuth2AccessTokenMapper oauth2AccessTokenMapper;
@Autowired
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
@Autowired
private RoleServiceImpl roleService;
@Autowired
private ResourceServiceImpl resourceService;
@Override
@Transactional
public OAuth2AccessTokenBO createToken(OAuth2CreateTokenDTO oauth2CreateTokenDTO) {
Integer userId = oauth2CreateTokenDTO.getUserId();
Integer userType = oauth2CreateTokenDTO.getUserType();
// 创建刷新令牌
OAuth2RefreshTokenDO oauth2RefreshTokenDO = createOAuth2RefreshToken(userId, userType);
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(userId, userType, oauth2RefreshTokenDO.getId());
// 转换返回
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
}
@Override
@Transactional
@ -72,76 +51,4 @@ public class OAuth2ServiceImpl implements OAuth2Service {
oauth2RefreshTokenMapper.updateToInvalid(userId, userType);
}
@Override
public OAuth2AccessTokenBO refreshToken(OAuth2RefreshTokenDTO oauth2RefreshTokenDTO) {
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectById(oauth2RefreshTokenDTO.getRefreshToken());
// 校验刷新令牌是否合法
if (refreshTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_NOT_FOUND.getCode());
}
if (refreshTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_EXPIRED.getCode());
}
if (!refreshTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH_INVALID_REFRESH_TOKEN_INVALID.getCode());
}
// 标记 refreshToken 对应的 accessToken 都不合法
oauth2AccessTokenMapper.updateToInvalidByRefreshToken(oauth2RefreshTokenDTO.getRefreshToken());
// 创建访问令牌
OAuth2AccessTokenDO oauth2AccessTokenDO = createOAuth2AccessToken(refreshTokenDO.getUserId(), refreshTokenDO.getUserType(),
refreshTokenDO.getId());
// 转换返回
return OAuth2Convert.INSTANCE.convertToAccessTokenWithExpiresIn(oauth2AccessTokenDO);
}
@Override
public OAuth2AuthenticationBO getAuthentication(OAuth2GetTokenDTO oauth2GetTokenDTO) {
OAuth2AccessTokenDO accessTokenDO = oauth2AccessTokenMapper.selectById(oauth2GetTokenDTO.getAccessToken());
if (accessTokenDO == null) { // 不存在
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_NOT_FOUND.getCode());
}
if (accessTokenDO.getExpiresTime().getTime() < System.currentTimeMillis()) { // 已过期
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_EXPIRED.getCode());
}
if (!accessTokenDO.getValid()) { // 无效
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_INVALID.getCode());
}
if (!oauth2GetTokenDTO.getUserType().equals(accessTokenDO.getUserType())) {
throw ServiceExceptionUtil.exception(AdminErrorCodeEnum.OAUTH2_INVALID_TOKEN_INVALID.getCode());
}
// 转换返回
return OAuth2Convert.INSTANCE.convertToAuthentication(accessTokenDO);
}
private OAuth2AccessTokenDO createOAuth2AccessToken(Integer userId, Integer userType, String refreshToken) {
OAuth2AccessTokenDO accessToken
= new OAuth2AccessTokenDO()
.setId(generateAccessToken())
.setRefreshToken(refreshToken)
.setUserId(userId).setUserType(userType)
.setExpiresTime(new Date(System.currentTimeMillis() + accessTokenExpireTimeMillis))
.setValid(true);
oauth2AccessTokenMapper.insert(accessToken);
return accessToken;
}
private OAuth2RefreshTokenDO createOAuth2RefreshToken(Integer userId, Integer userType) {
OAuth2RefreshTokenDO refreshToken
= new OAuth2RefreshTokenDO()
.setId(generateRefreshToken())
.setUserId(userId).setUserType(userType)
.setExpiresTime(new Date(System.currentTimeMillis() + refreshTokenExpireTimeMillis))
.setValid(true);
oauth2RefreshTokenMapper.insert(refreshToken);
return refreshToken;
}
private String generateAccessToken() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
private String generateRefreshToken() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}

View File

@ -102,25 +102,4 @@ public class AdminController {
return success(adminService.deleteAdmin(AdminSecurityContextHolder.getContext().getAdminId(), id));
}
@GetMapping("/role_list")
@ApiOperation(value = "指定管理员拥有的角色列表")
@ApiImplicitParam(name = "id", value = "管理员编号", required = true, example = "1")
public CommonResult<List<AdminRoleVO>> roleList(@RequestParam("id") Integer id) {
// 获得所有角色列表
List<RoleBO> allRoleList = roleService.getRoleList();
// 获得管理员的角色数组
Set<Integer> adminRoleIdSet = CollectionUtil.convertSet(adminService.getRoleList(id), RoleBO::getId);
// 转换出返回结果
List<AdminRoleVO> result = AdminConvert.INSTANCE.convert(allRoleList);
// 设置每个角色是否赋予给改管理员
result.forEach(adminRoleVO -> adminRoleVO.setAssigned(adminRoleIdSet.contains(adminRoleVO.getId())));
return success(result);
}
@PostMapping("/assign_role")
@ApiOperation(value = "分配给管理员角色")
public CommonResult<Boolean> assignRole(AdminAssignRoleDTO adminAssignRoleDTO) {
return success(adminService.assignAdminRole(AdminSecurityContextHolder.getContext().getAdminId(), adminAssignRoleDTO));
}
}