Merge remote-tracking branch 'origin/master'
commit
5777e65e27
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.mall.admin;
|
package cn.iocoder.mall.admin.application;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.mall.admin.config;
|
package cn.iocoder.mall.admin.application.config;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
import cn.iocoder.common.framework.config.GlobalExceptionHandler;
|
||||||
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
import cn.iocoder.mall.admin.sdk.interceptor.AdminSecurityInterceptor;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.mall.admin.config;
|
package cn.iocoder.mall.admin.application.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
|
@ -1,6 +1,9 @@
|
||||||
package cn.iocoder.mall.admin.controller;
|
package cn.iocoder.mall.admin.application.controller;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
||||||
|
import cn.iocoder.mall.admin.application.convert.AdminConvert;
|
||||||
|
import cn.iocoder.mall.admin.application.vo.AdminInfoVO;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
@ -12,8 +15,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
public class AdminController {
|
public class AdminController {
|
||||||
|
|
||||||
@GetMapping("/info")
|
@GetMapping("/info")
|
||||||
public CommonResult<Void> info() {
|
public CommonResult<AdminInfoVO> info() {
|
||||||
return null;
|
return CommonResult.success(AdminConvert.INSTANCE.convert(AdminSecurityContextHolder.getContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
package cn.iocoder.mall.admin.controller;
|
package cn.iocoder.mall.admin.application.controller;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||||
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
|
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
|
||||||
import cn.iocoder.mall.admin.convert.PassportConvert;
|
import cn.iocoder.mall.admin.application.convert.PassportConvert;
|
||||||
import cn.iocoder.mall.admin.vo.PassportLoginVO;
|
import cn.iocoder.mall.admin.application.vo.PassportLoginVO;
|
||||||
import com.alibaba.dubbo.config.annotation.Reference;
|
import com.alibaba.dubbo.config.annotation.Reference;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
|
@ -0,0 +1,61 @@
|
||||||
|
package cn.iocoder.mall.admin.application.controller;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.admin.api.ResourceService;
|
||||||
|
import cn.iocoder.mall.admin.api.bo.ResourceBO;
|
||||||
|
import cn.iocoder.mall.admin.api.constant.ResourceType;
|
||||||
|
import cn.iocoder.mall.admin.application.convert.ResourceConvert;
|
||||||
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
||||||
|
import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO;
|
||||||
|
import com.alibaba.dubbo.config.annotation.Reference;
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("admin/resource")
|
||||||
|
@Api("资源模块")
|
||||||
|
public class ResourceController {
|
||||||
|
|
||||||
|
@Reference
|
||||||
|
private ResourceService resourceService;
|
||||||
|
|
||||||
|
@GetMapping("/admin_menu_tree")
|
||||||
|
@ApiOperation(value = "获得管理员拥有的菜单权限", notes = "以树结构返回")
|
||||||
|
public CommonResult<List<AdminMenuTreeNodeVO>> adminMenuTree() {
|
||||||
|
List<ResourceBO> resources = resourceService.getResourceByTypeAndRoleIds(ResourceType.MENU, AdminSecurityContextHolder.getContext().getRoleIds());
|
||||||
|
// 创建 AdminMenuTreeNodeVO Map
|
||||||
|
Map<Integer, AdminMenuTreeNodeVO> treeNodeMap = resources.stream().collect(Collectors.toMap(ResourceBO::getId, ResourceConvert.INSTANCE::convert));
|
||||||
|
// 处理父子关系
|
||||||
|
treeNodeMap.values().stream().filter(node -> {
|
||||||
|
return node.getPid() != 0; // TODO magic number
|
||||||
|
}).forEach((childNode) -> {
|
||||||
|
// 获得父节点
|
||||||
|
AdminMenuTreeNodeVO parentNode = treeNodeMap.get(childNode.getPid());
|
||||||
|
if (parentNode.getChildren() == null) { // 初始化 children 数组
|
||||||
|
parentNode.setChildren(new ArrayList<>());
|
||||||
|
}
|
||||||
|
// 将自己添加到父节点中
|
||||||
|
parentNode.getChildren().add(childNode);
|
||||||
|
});
|
||||||
|
// 获得到所有的根节点
|
||||||
|
List<AdminMenuTreeNodeVO> rootNodes = treeNodeMap.values().stream().filter(node -> {
|
||||||
|
return node.getPid() == 0; // TODO magic number
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
return CommonResult.success(rootNodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/admin_url_list")
|
||||||
|
@ApiOperation(value = "获得管理员拥有的 URL 权限列表")
|
||||||
|
public CommonResult adminUrlList() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cn.iocoder.mall.admin.application.convert;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContext;
|
||||||
|
import cn.iocoder.mall.admin.application.vo.AdminInfoVO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface AdminConvert {
|
||||||
|
|
||||||
|
AdminConvert INSTANCE = Mappers.getMapper(AdminConvert.class);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
AdminInfoVO convert(AdminSecurityContext adminSecurityContext);
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package cn.iocoder.mall.admin.convert;
|
package cn.iocoder.mall.admin.application.convert;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
|
import cn.iocoder.mall.admin.api.bo.OAuth2AccessTokenBO;
|
||||||
import cn.iocoder.mall.admin.vo.PassportLoginVO;
|
import cn.iocoder.mall.admin.application.vo.PassportLoginVO;
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
import org.mapstruct.Mappings;
|
import org.mapstruct.Mappings;
|
||||||
import org.mapstruct.factory.Mappers;
|
import org.mapstruct.factory.Mappers;
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cn.iocoder.mall.admin.application.convert;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.bo.ResourceBO;
|
||||||
|
import cn.iocoder.mall.admin.application.vo.AdminMenuTreeNodeVO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ResourceConvert {
|
||||||
|
|
||||||
|
ResourceConvert INSTANCE = Mappers.getMapper(ResourceConvert.class);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
AdminMenuTreeNodeVO convert(ResourceBO resourceBO);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package cn.iocoder.mall.admin.application.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ApiModel("管理员信息 VO")
|
||||||
|
public class AdminInfoVO {
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "管理员比那好", required = true, example = "1")
|
||||||
|
private Integer adminId;
|
||||||
|
@ApiModelProperty(value = "角色编号的数组", required = true, example = "[1, 2]")
|
||||||
|
private Set<Integer> roleIds;
|
||||||
|
|
||||||
|
public Integer getAdminId() {
|
||||||
|
return adminId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminInfoVO setAdminId(Integer adminId) {
|
||||||
|
this.adminId = adminId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getRoleIds() {
|
||||||
|
return roleIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminInfoVO setRoleIds(Set<Integer> roleIds) {
|
||||||
|
this.roleIds = roleIds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package cn.iocoder.mall.admin.application.vo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AdminMenuTreeNodeVO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜单编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 彩蛋名
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* 操作
|
||||||
|
*/
|
||||||
|
private String handler;
|
||||||
|
/**
|
||||||
|
* 父菜单编号
|
||||||
|
*/
|
||||||
|
private Integer pid;
|
||||||
|
/**
|
||||||
|
* 子节点数组
|
||||||
|
*/
|
||||||
|
private List<AdminMenuTreeNodeVO> children;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminMenuTreeNodeVO setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminMenuTreeNodeVO setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminMenuTreeNodeVO setHandler(String handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AdminMenuTreeNodeVO> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminMenuTreeNodeVO setChildren(List<AdminMenuTreeNodeVO> children) {
|
||||||
|
this.children = children;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPid() {
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminMenuTreeNodeVO setPid(Integer pid) {
|
||||||
|
this.pid = pid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.iocoder.mall.admin.vo;
|
package cn.iocoder.mall.admin.application.vo;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
|
@ -5,6 +5,7 @@ import cn.iocoder.common.framework.util.HttpUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import cn.iocoder.mall.admin.api.OAuth2Service;
|
import cn.iocoder.mall.admin.api.OAuth2Service;
|
||||||
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
|
import cn.iocoder.mall.admin.api.bo.OAuth2AuthenticationBO;
|
||||||
|
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||||
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContext;
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContext;
|
||||||
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
import cn.iocoder.mall.admin.sdk.context.AdminSecurityContextHolder;
|
||||||
import com.alibaba.dubbo.config.annotation.Reference;
|
import com.alibaba.dubbo.config.annotation.Reference;
|
||||||
|
@ -38,6 +39,11 @@ public class AdminSecurityInterceptor extends HandlerInterceptorAdapter {
|
||||||
// 添加到 AdminSecurityContext
|
// 添加到 AdminSecurityContext
|
||||||
AdminSecurityContext context = new AdminSecurityContext(authentication.getAdminId(), authentication.getRoleIds());
|
AdminSecurityContext context = new AdminSecurityContext(authentication.getAdminId(), authentication.getRoleIds());
|
||||||
AdminSecurityContextHolder.setContext(context);
|
AdminSecurityContextHolder.setContext(context);
|
||||||
|
} else {
|
||||||
|
String url = request.getRequestURI();
|
||||||
|
if (!url.equals("/admin/passport/login")) { // TODO 临时写死。非登陆接口,必须已经认证身份,不允许匿名访问
|
||||||
|
throw new ServiceException(AdminErrorCodeEnum.OAUTH_NOT_LOGIN.getCode(), AdminErrorCodeEnum.OAUTH_NOT_LOGIN.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 校验是否需要已授权
|
// 校验是否需要已授权
|
||||||
checkPermission(request, authentication);
|
checkPermission(request, authentication);
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package cn.iocoder.mall.admin.api;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.bo.ResourceBO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface ResourceService {
|
||||||
|
|
||||||
|
List<ResourceBO> getResourceByTypeAndRoleIds(Integer type, Set<Integer> roleIds);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
package cn.iocoder.mall.admin.api.bo;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源 BO
|
||||||
|
*/
|
||||||
|
public class ResourceBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源编号
|
||||||
|
*/
|
||||||
|
private Integer id;
|
||||||
|
/**
|
||||||
|
* 资源名字(标识)
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
/**
|
||||||
|
* 排序
|
||||||
|
*/
|
||||||
|
private Integer sort;
|
||||||
|
/**
|
||||||
|
* 展示名
|
||||||
|
*/
|
||||||
|
private String displayName;
|
||||||
|
/**
|
||||||
|
* 添加时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
/**
|
||||||
|
* 父级资源编号
|
||||||
|
*/
|
||||||
|
private Integer pid;
|
||||||
|
/**
|
||||||
|
* 操作
|
||||||
|
*/
|
||||||
|
private String handler;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setType(Integer type) {
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setSort(Integer sort) {
|
||||||
|
this.sort = sort;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setDisplayName(String displayName) {
|
||||||
|
this.displayName = displayName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setCreateTime(Date createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPid() {
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setPid(Integer pid) {
|
||||||
|
this.pid = pid;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceBO setHandler(String handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ public enum AdminErrorCodeEnum {
|
||||||
OAUTH_INVALID_TOKEN_EXPIRED(1002001012, "访问令牌已过期"),
|
OAUTH_INVALID_TOKEN_EXPIRED(1002001012, "访问令牌已过期"),
|
||||||
OAUTH_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
|
OAUTH_INVALID_TOKEN_INVALID(1002001013, "访问令牌已失效"),
|
||||||
OAUTH_INVALID_PERMISSION(1002001014, "没有该操作权限"), // TODO 芋艿,临时放在 OAUTH2 模块,理论来说,OAUTH2 只做认证,不做鉴权。
|
OAUTH_INVALID_PERMISSION(1002001014, "没有该操作权限"), // TODO 芋艿,临时放在 OAUTH2 模块,理论来说,OAUTH2 只做认证,不做鉴权。
|
||||||
|
OAUTH_NOT_LOGIN(1002001015, "账号未登陆"),
|
||||||
|
|
||||||
OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
|
OAUTH_INVALID_TOKEN(1002001020, ""), // 预留
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cn.iocoder.mall.admin.api.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源类型
|
||||||
|
*/
|
||||||
|
public interface ResourceType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 彩蛋
|
||||||
|
*/
|
||||||
|
Integer MENU = 1;
|
||||||
|
/**
|
||||||
|
* URL
|
||||||
|
*/
|
||||||
|
Integer URL = 2;
|
||||||
|
|
||||||
|
}
|
|
@ -49,6 +49,12 @@
|
||||||
<version>${org.mapstruct.version}</version>
|
<version>${org.mapstruct.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>27.0.1-jre</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cn.iocoder.mall.admin.convert;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.bo.ResourceBO;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ResourceDO;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
|
import org.mapstruct.factory.Mappers;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ResourceConvert {
|
||||||
|
|
||||||
|
ResourceConvert INSTANCE = Mappers.getMapper(ResourceConvert.class);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
ResourceBO convert(ResourceDO resourceDO);
|
||||||
|
|
||||||
|
@Mappings({})
|
||||||
|
List<ResourceBO> convert(List<ResourceDO> resourceDOs);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package cn.iocoder.mall.admin.dao;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ResourceDO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ResourceMapper {
|
||||||
|
|
||||||
|
ResourceDO selectByTypeAndHandler(@Param("type") Integer type,
|
||||||
|
@Param("handler") String handler);
|
||||||
|
|
||||||
|
List<ResourceDO> selectListByTypeAndRoleIds(@Param("type") Integer type,
|
||||||
|
@Param("roleIds") Set<Integer> roleIds);
|
||||||
|
|
||||||
|
}
|
|
@ -11,4 +11,6 @@ public interface RoleResourceMapper {
|
||||||
|
|
||||||
List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler);
|
List<RoleResourceDO> selectByResourceHandler(@Param("resourceHandler") String resourceHandler);
|
||||||
|
|
||||||
|
List<RoleResourceDO> selectRoleByResourceId(@Param("resourceId") Integer resourceId);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,21 +1,25 @@
|
||||||
package cn.iocoder.mall.admin.dataobject;
|
package cn.iocoder.mall.admin.dataobject;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.dataobject.BaseDO;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源实体
|
* 资源实体
|
||||||
*/
|
*/
|
||||||
public class ResourceDO {
|
public class ResourceDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 资源类型 - 菜单
|
* 资源类型 - 菜单
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static final Integer TYPE_MENU = 1;
|
public static final Integer TYPE_MENU = 1;
|
||||||
/**
|
/**
|
||||||
* 资源类型 - 操作
|
* 资源类型 - 操作
|
||||||
*
|
*
|
||||||
* 例如,按钮。
|
* 例如,按钮。
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static final Integer TYPE_OPERATION = 2;
|
public static final Integer TYPE_OPERATION = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +27,7 @@ public class ResourceDO {
|
||||||
*/
|
*/
|
||||||
private Integer id;
|
private Integer id;
|
||||||
/**
|
/**
|
||||||
* 资源名字
|
* 资源名字(标识)
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +54,7 @@ public class ResourceDO {
|
||||||
* 操作
|
* 操作
|
||||||
*
|
*
|
||||||
* 当资源类型为【菜单】时,handler 配置为界面 URL ,或者前端组件名
|
* 当资源类型为【菜单】时,handler 配置为界面 URL ,或者前端组件名
|
||||||
* 当资源类型为【操作】时,handler 配置为后端 URL 。举个例子,如果有一个「创建管理员」的表单,那么前端界面上的按钮可以根据这个 url 判断是否展示,后端接收到该 url 的请求时会判断是否有权限。
|
* 当资源类型为【URL】时,handler 配置为后端 URL 。举个例子,如果有一个「创建管理员」的表单,那么前端界面上的按钮可以根据这个 url 判断是否展示,后端接收到该 url 的请求时会判断是否有权限。
|
||||||
*/
|
*/
|
||||||
private String handler;
|
private String handler;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import cn.iocoder.common.framework.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.common.framework.vo.CommonResult;
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
import cn.iocoder.mall.admin.api.AdminService;
|
import cn.iocoder.mall.admin.api.AdminService;
|
||||||
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
import cn.iocoder.mall.admin.api.constant.AdminErrorCodeEnum;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.AdminDO;
|
||||||
import cn.iocoder.mall.admin.dao.AdminMapper;
|
import cn.iocoder.mall.admin.dao.AdminMapper;
|
||||||
import cn.iocoder.mall.admin.dao.AdminRoleMapper;
|
import cn.iocoder.mall.admin.dao.AdminRoleMapper;
|
||||||
import cn.iocoder.mall.admin.dataobject.AdminDO;
|
|
||||||
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
|
import cn.iocoder.mall.admin.dataobject.AdminRoleDO;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
|
@ -14,7 +14,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@com.alibaba.dubbo.config.annotation.Service
|
@com.alibaba.dubbo.config.annotation.Service
|
||||||
|
@ -39,6 +42,8 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
||||||
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
|
private OAuth2RefreshTokenMapper oauth2RefreshTokenMapper;
|
||||||
@Autowired
|
@Autowired
|
||||||
private RoleServiceImpl roleService;
|
private RoleServiceImpl roleService;
|
||||||
|
@Autowired
|
||||||
|
private ResourceServiceImpl resourceService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<OAuth2AccessTokenBO> getAccessToken(String username, String password) {
|
public CommonResult<OAuth2AccessTokenBO> getAccessToken(String username, String password) {
|
||||||
|
@ -76,15 +81,17 @@ public class OAuth2ServiceImpl implements OAuth2Service {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommonResult<Boolean> checkPermission(Integer adminId, Set<Integer> roleIds, String url) {
|
public CommonResult<Boolean> checkPermission(Integer adminId, Set<Integer> roleIds, String url) {
|
||||||
// 避免传入的是空集合
|
// 如果未配置该资源,说明无需权限控制。
|
||||||
if (roleIds == null) {
|
ResourceDO resource = resourceService.getResourceByTypeAndHandler(ResourceDO.TYPE_OPERATION, url);
|
||||||
roleIds = Collections.emptySet();
|
if (resource == null) {
|
||||||
}
|
|
||||||
// 校验权限
|
|
||||||
List<RoleResourceDO> roleResourceDOs = roleService.getRoleByResourceHandler(url);
|
|
||||||
if (roleResourceDOs.isEmpty()) { // 任何角色,都可以访问。TODO 后面调整下,如果未配置的资源,直接不校验权限
|
|
||||||
return CommonResult.success(true);
|
return CommonResult.success(true);
|
||||||
}
|
}
|
||||||
|
// 资源存在,结果无角色,说明没有权限。
|
||||||
|
if (roleIds == null || roleIds.isEmpty()) {
|
||||||
|
return ServiceExceptionUtil.error(AdminErrorCodeEnum.OAUTH_INVALID_PERMISSION.getCode());
|
||||||
|
}
|
||||||
|
// 校验是否有资源对应的角色,即 RBAC 。
|
||||||
|
List<RoleResourceDO> roleResourceDOs = roleService.getRoleByResourceId(resource.getId());
|
||||||
for (RoleResourceDO roleResourceDO : roleResourceDOs) {
|
for (RoleResourceDO roleResourceDO : roleResourceDOs) {
|
||||||
if (roleIds.contains(roleResourceDO.getRoleId())) {
|
if (roleIds.contains(roleResourceDO.getRoleId())) {
|
||||||
return CommonResult.success(true);
|
return CommonResult.success(true);
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package cn.iocoder.mall.admin.service;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.admin.api.ResourceService;
|
||||||
|
import cn.iocoder.mall.admin.api.bo.ResourceBO;
|
||||||
|
import cn.iocoder.mall.admin.convert.ResourceConvert;
|
||||||
|
import cn.iocoder.mall.admin.dao.ResourceMapper;
|
||||||
|
import cn.iocoder.mall.admin.dataobject.ResourceDO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@com.alibaba.dubbo.config.annotation.Service
|
||||||
|
public class ResourceServiceImpl implements ResourceService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceMapper resourceMapper;
|
||||||
|
|
||||||
|
public ResourceDO getResourceByTypeAndHandler(Integer type, String handler) {
|
||||||
|
return resourceMapper.selectByTypeAndHandler(type, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceBO> getResourceByTypeAndRoleIds(Integer type, Set<Integer> roleIds) {
|
||||||
|
if (roleIds == null || roleIds.isEmpty()) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return ResourceConvert.INSTANCE.convert(resourceMapper.selectListByTypeAndRoleIds(type, roleIds));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,4 +19,8 @@ public class RoleServiceImpl implements RoleService {
|
||||||
return roleResourceMapper.selectByResourceHandler(resourceHandler);
|
return roleResourceMapper.selectByResourceHandler(resourceHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<RoleResourceDO> getRoleByResourceId(Integer resourceId) {
|
||||||
|
return roleResourceMapper.selectRoleByResourceId(resourceId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="cn.iocoder.mall.admin.dao.ResourceMapper">
|
||||||
|
|
||||||
|
<!--<insert id="insert" parameterType="UserDO" useGeneratedKeys="true" keyProperty="id">-->
|
||||||
|
<!--INSERT INTO users (-->
|
||||||
|
<!--id, mobile, create_time-->
|
||||||
|
<!--) VALUES (-->
|
||||||
|
<!--#{id}, #{mobile}, #{createTime}-->
|
||||||
|
<!--)-->
|
||||||
|
<!--</insert>-->
|
||||||
|
|
||||||
|
<select id="selectByTypeAndHandler" resultType="ResourceDO">
|
||||||
|
SELECT
|
||||||
|
id, name, type, sort, display_name,
|
||||||
|
create_time, pid, handler
|
||||||
|
FROM resource
|
||||||
|
WHERE type = #{type}
|
||||||
|
AND handler = #{handler}
|
||||||
|
AND deleted = 0
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectListByTypeAndRoleIds" resultType="ResourceDO">
|
||||||
|
SELECT
|
||||||
|
r.id, r.name, r.type, r.sort, r.display_name,
|
||||||
|
r.create_time, r.pid, r.handler
|
||||||
|
FROM resource r, role_resource rr
|
||||||
|
WHERE r.type = #{type}
|
||||||
|
AND deleted = 0
|
||||||
|
AND rr.role_id IN
|
||||||
|
<foreach item="roleId" collection="roleIds" separator="," open="(" close=")" index="">
|
||||||
|
#{roleId}
|
||||||
|
</foreach>
|
||||||
|
AND r.id = rr.resource_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
|
@ -18,4 +18,11 @@
|
||||||
AND r.id = rr.resource_id
|
AND r.id = rr.resource_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectRoleByResourceId" parameterType="Integer" resultType="RoleResourceDO">
|
||||||
|
SELECT
|
||||||
|
id, role_id, resource_id
|
||||||
|
FROM role_resource
|
||||||
|
WHERE resource_id = #{resourceId}
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
|
@ -44,6 +44,11 @@
|
||||||
<artifactId>jackson-annotations</artifactId>
|
<artifactId>jackson-annotations</artifactId>
|
||||||
<version>2.9.7</version>
|
<version>2.9.7</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--<dependency>-->
|
||||||
|
<!--<groupId>com.baomidou</groupId>-->
|
||||||
|
<!--<artifactId>mybatis-plus-support</artifactId>-->
|
||||||
|
<!--<version>2.3</version>-->
|
||||||
|
<!--</dependency>-->
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ public enum SysErrorCodeEnum {
|
||||||
|
|
||||||
SYS_ERROR(2001001000, "服务端发生异常"),
|
SYS_ERROR(2001001000, "服务端发生异常"),
|
||||||
MISSING_REQUEST_PARAM_ERROR(2001001001, "参数缺失"),
|
MISSING_REQUEST_PARAM_ERROR(2001001001, "参数缺失"),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final int code;
|
private final int code;
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package cn.iocoder.common.framework.dataobject;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础实体对象
|
||||||
|
*/
|
||||||
|
public class BaseDO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
/**
|
||||||
|
* 最后更新时间
|
||||||
|
*/
|
||||||
|
private Date updateTime;
|
||||||
|
private Boolean deleted;
|
||||||
|
|
||||||
|
public Date getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseDO setCreateTime(Date createTime) {
|
||||||
|
this.createTime = createTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getUpdateTime() {
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseDO setUpdateTime(Date updateTime) {
|
||||||
|
this.updateTime = updateTime;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getDeleted() {
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseDO setDeleted(Boolean deleted) {
|
||||||
|
this.deleted = deleted;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue