同步操作将从 freestylewill/open-scope 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
OpenScope是一种轻量级、易维护的数据权限的解决方案,它能处理比较复杂的权限操作逻辑。兼容操作权限Shiro等框架。
OpenScope提供了一种基于SQL的智能添加权限范围列的方案,相对原始的数据权限方案,它是轻量级的,它只有一些配置代码,同时它也是提高了代码的可维护性。另外它不需要额外的更改您的程序结构,就能轻松使您的项目支持数据权限操作。
什么是操作权限,什么是数据权限详细见WIKI 简介
将数据权限的粒度控制到数据列上。[-]
对ORM-HIBERNATE兼容或者对ORM-JDBC(任选其一)[-]
(注:[-] 表示待开发或者正在开发中,[√]表示已完成)
ORM-Mybatis过滤原理:通过对SQL智能的添加权限列来到的基于权限范围的数据过滤。
考虑性能的原因:
我们给了一套默认的权限配置,对查询多条数据只进行数据过滤操作,对单挑数据的操作只执行转换操作和认证操作。这对Spring-Cloud相关的微服务项目很有帮助。减少了各个模块之间相互调用的次数,提升了服务器的处理能力和响应能力。 但是如果您不考虑性能的问题,而是考虑权限认证操作的流程的完整性。你仍然可以为每一个请求开启过滤、转换,认证三个操作。
(注:可以根据业务的范围或者实际需求进行调整,ORM-Mybatis过滤是基于SQL,所以请务必要保证您的查询结果集合里存在配置的范围列字段,否则执行权限范围过滤的过程中会抛出找不到范围列的异常信息。[SQLException: Column 您配置的权限范围列 not found异常。])
OpenScope分为多个组件
权限范围认证器(IScopeAuthenticator)
主要用于向您的认证中心发起认证消息。你可以在这里面写一些您的认证中心的发起逻辑。
权限范围提取器(IScopeExtractor)
主要用于从您的认证中心提取业务范围数据,并将其设置到List<Scope> scopeCollections中。用于权限拦截器动态拼装权限范围等内容。
权限范围转换器(IScopeConverter)
主要用于业务对象ID转换范围对象ID。
错误异常处理器(ThrowableHandler)
主要用于统一处理权限认证的错误异常类
ORM-权限拦截器 (Permission)
智能的对SQL进行拦截,并为其添加权限范围过滤列。
<!-- openScope依赖 -->
<dependency>
<groupId>com.mofum.scope</groupId>
<artifactId>scope-boot-starter</artifactId>
<version>1.0.0.1.RELEASE</version>
</dependency>
(注:如果是SpringCloud项目,如果子项目不需要Mybatis,请移除相关的依赖)
<!-- openScope依赖(不包含orm-mybatis) -->
<dependency>
<groupId>com.mofum.scope</groupId>
<artifactId>scope-boot-starter</artifactId>
<version>1.0.0.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>com.mofum.scope</groupId>
<artifactId>scope-orm-mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>com.mofum.scope</groupId>
<artifactId>scope-autoconfiure</artifactId>
</exclusion>
</exclusions>
</dependency>
以下内容详细请见:https://gitee.com/mofum/open-scope-demo
@SpringBootApplication
@ComponentScan(value = {
"com.mofum.scope.controller",//控制器
"com.mofum.scope.service",//本地逻辑具体业务
"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();
}
}
@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
@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;
}
}
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;
}
}
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;
}
}
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;
}
}
@Configuration
public class MybatisScopeAutoConfiguration {
@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;
public MybatisScopeAutoConfiguration() {
}
@PostConstruct
public void addTestInterceptor() {
PermissionInterceptor interceptor = new PermissionInterceptor();
interceptor.setRestructureProcessor(new DruidRestructureProcessor());
Iterator var3 = this.sqlSessionFactoryList.iterator();
while (var3.hasNext()) {
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3.next();
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
}
@Component
@Aspect
public class ServiceAspectJ extends AbstractColumnAspectJ {
//配置业务切面
@Override
@Pointcut("execution(* com.mofum.scope.service..*.*(..))")
public void config() {
}
}
@Component
@Aspect
public class ControllerAspectJ extends AbstractControllerAspectJ {
private ThrowableHandler throwableHandler;
//配置控制切面
@Override
@Pointcut("execution(* com.mofum.scope.controller..*.*(..))")
public void config() {
}
@Override
public ThrowableHandler getThrowableHandler() {
if(throwableHandler == null){
throwableHandler = new ControllerThrowableHandler();
}
return throwableHandler;
}
@Override
public void setThrowableHandler(ThrowableHandler throwableHandler) {
this.throwableHandler = throwableHandler;
}
}
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;
}
}
QQ交流群:1062019634(200人)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。