1 Star 0 Fork 102

asling_zhang / open-scope

forked from mofum / open-scope 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 10.75 KB
一键复制 编辑 原始数据 按行查看 历史
玉米 提交于 2019-03-29 09:28 . 更新 README.md

open-scope

介绍

OpenScope是一种轻量级、易维护的数据权限的解决方案,它能处理比较复杂的权限操作逻辑。兼容操作权限Shiro等框架。

OpenScope提供了一种基于SQL的智能添加权限范围列的方案,相对原始的数据权限方案,它是轻量级的,它只有一些配置代码,同时它也是提高了代码的可维护性。另外它不需要额外的更改您的程序结构,就能轻松使您的项目支持数据权限操作。

什么是操作权限,什么是数据权限详细见WIKI 简介

原理:

过滤原理:通过对SQL智能的添加权限列来到的基于权限范围的数据过滤。

以下是默认流程(可以根据业务的范围或者实际需求进行调整):

组件的过滤流程:
  1. 控制层请求 >
  2. 控制层切面 >
  3. 执行范围提取器获得权限范围 >
  4. 将权限范围设置到scopeCollections中 >
  5. 进入业务切面 >
  6. 将业务切面类上的TableScope内容完善到scopeCollections中 >
  7. 进入权限拦截器 >
  8. 根据scopeCollections的内容进行智能拼装SQL
组件的认证流程
  1. 控制层请求 >
  2. 控制层切面 >
  3. 进入权限范围转换器 获得业务对象,将业务对象转换成范围对象 >
  4. 将范围对象交给权限认证器 >
  5. 认证器向您的认证服务中心提供的认证权限的接口发起请求 >
  6. 您的具体业务逻辑 >
  7. 如果认证器里没有抛出异常,则认证成功 >
  8. 如果认证器里抛出异常,则认证失败 >

软件架构

OpenScope分为多个组件

  • 权限范围认证器(IScopeAuthenticator)

主要用于向您的认证中心发起认证消息。你可以在这里面写一些您的认证中心的发起逻辑。

  • 权限范围提取器(IScopeExtractor)

    主要用于从您的认证中心提取业务范围数据,并将其设置到List scopeCollections中。用于权限拦截器动态拼装权限范围等内容。

  • 权限范围转换器(IScopeConverter)

    主要用于业务对象ID转换范围对象ID。

  • 错误异常处理器(ThrowableHandler)

    主要用于统一处理权限认证的错误异常类

  • 权限拦截器

智能的对SQL进行拦截,并为其添加权限范围过滤列。

子包说明

  • scope-common (公用的模型定义)
  • scope-com.mofum.scope.annotation(公用的注解)
  • scope-orm-mybatis(ORM框架有关的内容)
  • scope-spring-web(Spring-web相关的内容)
  • scope-autoconfigure(自动配置内容)
  • scope-boot-starter(SpringBoot相关内容)

安装方法(部分)

        <!-- openScope依赖 -->
         <dependency>
            <groupId>com.mofum.scope</groupId>
            <artifactId>scope-boot-starter</artifactId>
            <version>${mofum-scope.version}</version>
        </dependency>
            

使用方法(SpringBoot版本)

以下内容详细请见:https://gitee.com/mofum/open-scope-demo

SpringBoot Application 类

@SpringBootApplication
@ComponentScan(value = {
        "com.mofum.scope.controller",//控制器
        "com.mofum.scope.service",//本地逻辑具体业务
        "com.mofum.scope.com.mofum.scope.config"
})
@MapperScan("com.mofum.scope.mapper")
@EnableAutoConfiguration
@EnableAspectJAutoProxy    //开启切面控制
public class Application {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(Application.class, args);

        IUserService userService = applicationContext.getBean(UserServiceImpl.class);

        userService.initTable();
    }
}

控制层(Controller)

@RestController
@RequestMapping("/user")
public class UserController extends ScopeController {

    public static Logger logger = LoggerFactory.getLogger(UserController.class);

    @Autowired
    IUserService userService;

    @RequestMapping("/add")
    public Object addUser(User user) {
        userService.addUser(user);
        return "SUCCESS";
    }

    @RequestMapping("/query")
    public Object query(UserDto userDto) {
        logger.info(userDto.toString());
        return userService.queryUser(userDto);
    }

    @RequestMapping("/scope/query")
    @QueryScope
    public Object scopeQuery(UserDto userDto) {
        logger.info(userDto.toString());
        return userService.queryUser(userDto);
    }

    @RequestMapping("/del")
    @UpdateScope(columns = {
            @ServiceColumn(value = "serviceIds")
    })
    public Object del(UserDto userDto) {
        logger.info(userDto.toString());
        return "SUCCESS";
    }
}

业务层(Service)

@Service
@TableScope(columns = {
        /**
         * @see com.mofum.scope.controller.ScopeController 中的extractorScopes()方法
         */
        @ColumnScope(type = "ScopeOne", value = "scope_one") //配置列type 是类型,scope_one是表中的列
})
public class UserServiceImpl implements IUserService {

    @Autowired
    UserMapper userMapper;

    @Override
    public void initTable() {
        userMapper.createTable();
    }

    @Override
    public void addUser(User user) {
        if (user != null) {
            user.setId(UUID.randomUUID().toString());
        }
        userMapper.insertUser(user);
    }

    @Override
    public List<User> queryUser(UserDto user) {
        return userMapper.queryUser(user);
    }

    @Override
    public int delete(UserDto userDto) {
        return 0;
    }
}

配置业务对象转换器(ScopeConvert)【必须】

public class ScopeController implements IScopeConverter<Object, RuntimeException> {

    @Override
    public List<Scope> convert2Scope(Object o) throws RuntimeException {
        //转换业务对象为ScopeId
        List<Scope> scopes = new ArrayList<>();
        Scope scope = new Scope();
        scope.setId("1");
        scope.setType("ScopeOne"); //Type和IUserService 中的注解ColumnScope要指定同一个注解才能生效
        scopes.add(scope);
        return scopes;
    }

}

配置SQL范围提取器(ScopeExtractor)【必须】

public class ScopeController implements IScopeExtractor<Object, RuntimeException> {

    
    @Override
    public List<? extends Scope> extractorScopes(Object o) throws RuntimeException {

        //提取权限数据范围

        //假设只有SCOPE_ONE只有权限范围1

        List<Scope> scopes = new ArrayList<>();
        Scope scope = new Scope();
        scope.setId("1");
        scope.setType("ScopeOne"); //Type和IUserService 中的注解ColumnScope要指定同一个注解才能生效
        scopes.add(scope);

        return scopes;
    }

}

配置认证器(ScopeAuthenticator)【必须】

public class ScopeController implements IScopeAuthenticator<List<Scope>, RuntimeException>{


    @Override
    public boolean testAccess(List<Scope> scopes) throws RuntimeException {

        //取用户ID
        String userId = getRequest().getParameter("userId");

        //取请求URL

        String url = getRequest().getRequestURI();


        boolean accessFlag = false;
        //验证权限逻辑
        for (Scope scope : scopes) {

            if (scope.getId().equals("2")) {
                return true;
            }

        }

        if (!accessFlag) {
            throw new RuntimeException("Operation failed!Cause no permission!(action :" + url + ")");
        }

        return accessFlag;
    }


    public HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    public HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }

}

配置权限拦截器(Config PermissionInterceptor )【必须】

@Configuration
public class MybatisScopeAutoConfiguration {

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    public MybatisScopeAutoConfiguration() {
    }

    @PostConstruct
    public void addTestInterceptor() {
        PermissionInterceptor interceptor = new PermissionInterceptor();
        Iterator var3 = this.sqlSessionFactoryList.iterator();

        while (var3.hasNext()) {
            SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3.next();
            sqlSessionFactory.getConfiguration().addInterceptor(com.mofum.scope.interceptor);
        }

    }
}

配置业务切面 (Config Scan Service Aspect)【必须】

@Component
@Aspect
public class ServiceAspectJ extends AbstractColumnAspectJ {

    //配置业务切面
    @Override
    @Pointcut("execution(* com.mofum.scope.service..*.*(..))")
    public void com.mofum.scope.config() {

    }
}

配置控制切面 (Config Scan Service Aspect)【必须】

@Component
@Aspect
public class ControllerAspectJ extends AbstractControllerAspectJ {

    private ThrowableHandler throwableHandler;

    //配置控制切面
    @Override
    @Pointcut("execution(* com.mofum.scope.controller..*.*(..))")
    public void com.mofum.scope.config() {

    }

    @Override
    public ThrowableHandler getThrowableHandler() {
        if(throwableHandler == null){
            throwableHandler = new ControllerThrowableHandler();
        }

        return throwableHandler;
    }

    @Override
    public void setThrowableHandler(ThrowableHandler throwableHandler) {
        this.throwableHandler = throwableHandler;
    }
}

配置异常处理器 (Config ErrorHandler) 【非必须】

public class ControllerThrowableHandler implements ThrowableHandler {

    @Override
    public void handler(Throwable throwable) throws Throwable {

        if (throwable != null) {
            getResponse().setCharacterEncoding("UTF-8");
            getResponse().getWriter().println(throwable.getMessage());
            throwable.printStackTrace();
        }

    }

    public HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    public HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }

}
Java
1
https://gitee.com/asling_zhang/open-scope.git
git@gitee.com:asling_zhang/open-scope.git
asling_zhang
open-scope
open-scope
master

搜索帮助