/**
* 自定义注解,作用于数据权限
*
* @author LZJ
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserDataPermission {
}
/**
* 拦截器
*
* @author LZJ
*/
@Data
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class DataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
private static final String[] KEYWORDS = {
"com.performance.mapper.passable",
"selectById"
};
/**
* 数据权限处理器
*/
private DataPermissionHandler dataPermissionHandler;
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
return;
}
String mapperShow = ms.getId();
//不判断权限的情况
if (shouldSkip(mapperShow)) {
return;
}
PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql);
mpBs.sql(this.parserSingle(mpBs.sql(), ms.getId()));
}
@Override
protected void processSelect(Select select, int index, String sql, Object obj) {
SelectBody selectBody = select.getSelectBody();
if (selectBody instanceof PlainSelect) {
this.setWhere((PlainSelect) selectBody, (String) obj);
} else if (selectBody instanceof SetOperationList) {
SetOperationList setOperationList = (SetOperationList) selectBody;
List<SelectBody> selectBodyList = setOperationList.getSelects();
selectBodyList.forEach(s -> this.setWhere((PlainSelect) s, (String) obj));
}
}
/**
* 设置 where 条件
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
*/
private void setWhere(PlainSelect plainSelect, String whereSegment) {
Expression sqlSegment = this.dataPermissionHandler.getSqlSegment(plainSelect, whereSegment);
if (null != sqlSegment) {
plainSelect.setWhere(sqlSegment);
}
}
/**
* 不判断权限的情况
*/
private boolean shouldSkip(String mapperShow) {
for (String keyword : KEYWORDS) {
if (mapperShow.contains(keyword)) {
return true;
}
}
return false;
}
}
/**
* 数据权限拦截处理器
*
* @author LZJ
*/
@Slf4j
public class DataPermissionHandler {
/**
* 获取数据权限 SQL 片段
*
* @param plainSelect 查询对象
* @param whereSegment 查询条件片段
* @return JSqlParser 条件表达式
*/
@SneakyThrows(Exception.class)
public Expression getSqlSegment(PlainSelect plainSelect, String whereSegment) {
log.debug("开始进行权限过滤mappedStatementId: {}", whereSegment);
//有权
String pass = " 1 = 1 ";
//无权
String refuse = " 1 = 2 ";
// 待执行 SQL Where 条件表达式
Expression where = plainSelect.getWhere();
if (where == null) {
where = new HexValue(pass);
}
log.debug("查询语句: {},where条件: {}", plainSelect, where);
Table fromItem = (Table) plainSelect.getFromItem();
// 有别名用别名,无别名用表名,防止字段冲突报错
Alias fromItemAlias = fromItem.getAlias();
String mainTableName = fromItemAlias == null ? fromItem.getName() : fromItemAlias.getName();
//获取mapper名称
String className = whereSegment.substring(0, whereSegment.lastIndexOf("."));
//获取当前mapper 的方法
Method[] methods = Class.forName(className).getMethods();
//获取方法名
String methodName = whereSegment.substring(whereSegment.lastIndexOf(".") + 1);
//获取token信息
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(RequestHeaderName.TOKEN);
RedisService redisService = SpringUtil.getBean(RedisService.class);
LoginToken loginToken = redisService.getCacheObject(TokenConstants.REDIS_KEY_PREFIX + token);
//回调的时候会是NULL
if (loginToken == null) {
return where;
}
//管理员看全部
if (loginToken.getSuperManager() == 1) {
return where;
}
RoleDataAndDeptBo roleDataPermissions = loginToken.getRoleDataPermissions();
if (roleDataPermissions == null
|| CollUtil.isEmpty(roleDataPermissions.getDataScope())) {
//无权查看
return new HexValue(refuse);
}
//1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限
Set<String> dataScope = roleDataPermissions.getDataScope();
Set<String> deptIdSet = roleDataPermissions.getDeptIdSet();
//全部数据权限
if (dataScope.contains(DataScopeType.ALL.getCode())) {
return where;
}
//变态需求,需要根据查询项不走数据权限
if ("xxx".equals(mainTableName)) {
String string = where.toString();
log.debug("where格式化: {}", string);
if (string.contains("AND 3 =")) {
return where;
}
}
//不包含本人数据权限
if (!dataScope.contains(DataScopeType.SELF.getCode())) {
if (CollUtil.isEmpty(deptIdSet)) {
//无权查看
where = new HexValue(refuse);
return where;
}
//遍历判断mapper 的所有方法,判断方法上是否有 UserDataPermission
for (Method m : methods) {
if (!Objects.equals(m.getName(), methodName)) {
continue;
}
UserDataPermission annotation = m.getAnnotation(UserDataPermission.class);
if (annotation == null) {
return where;
}
//部门权限
ItemsList deptList = new ExpressionList(deptIdSet.stream().map(StringValue::new).collect(Collectors.toList()));
InExpression inExpressiondept = new InExpression(new Column(mainTableName + ".department_id"), deptList);
return new AndExpression(where, inExpressiondept);
}
} else {
//包含用户权限,不限部门权限
//是否只包含用户权限
boolean flag = CollUtil.isEmpty(deptIdSet);
//遍历判断mapper 的所有方法,判断方法上是否有 UserDataPermission
for (Method m : methods) {
if (!Objects.equals(m.getName(), methodName)) {
continue;
}
UserDataPermission annotation = m.getAnnotation(UserDataPermission.class);
if (annotation == null) {
return where;
}
//用户权限
EqualsTo usesEqualsTo = new EqualsTo();
usesEqualsTo.setLeftExpression(new Column(mainTableName + ".creator_id"));
usesEqualsTo.setRightExpression(new StringValue(loginToken.getUserId()));
if (flag) {
return new AndExpression(where, usesEqualsTo);
}
//部门权限
ItemsList deptList = new ExpressionList(deptIdSet.stream().map(StringValue::new).collect(Collectors.toList()));
InExpression inExpressiondept = new InExpression(new Column(mainTableName + ".department_id"), deptList);
//部门权限or用户权限
OrExpression orExpression = new OrExpression();
orExpression.setLeftExpression(inExpressiondept);
orExpression.setRightExpression(usesEqualsTo);
//救命的sql拼接 https://www.cnblogs.com/hanzhe/articles/17037141.html
Parenthesis parenthesis = new Parenthesis(orExpression);
return new AndExpression(where, parenthesis);
}
}
//说明无权查看,
where = new HexValue(refuse);
return where;
}
}
@Configuration
public class MybatisPlusInterceptorConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//如果用了分页插件注意先 add TenantLineInnerInterceptor 再 add PaginationInnerInterceptor
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//数据权限处理
interceptor.addInnerInterceptor(dataPermissionInterceptor());
//配置多租户
interceptor.addInnerInterceptor(tenantLineInnerInterceptor());
//分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
//配置乐观锁
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
return interceptor;
}
/**
* 分页插件,自动识别数据库类型
*/
public PaginationInnerInterceptor paginationInnerInterceptor() {
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
// 分页合理化
paginationInnerInterceptor.setOverflow(true);
paginationInnerInterceptor.setOptimizeJoin(true);
paginationInnerInterceptor.setDbType(DbType.POSTGRE_SQL);
return paginationInnerInterceptor;
}
/**
* 乐观锁插件
*/
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor() {
return new OptimisticLockerInnerInterceptor();
}
/**
* 多租户插件
*/
public TenantLineInnerInterceptor tenantLineInnerInterceptor() {
return new TenantLineInnerInterceptor(new MultiTenantHandler());
}
/**
* 数据权限
*/
public DataPermissionInterceptor dataPermissionInterceptor() {
return new DataPermissionInterceptor(new DataPermissionHandler());
}
}
/**
* 自定义 Mapper 接口, 实现 自定义扩展
*
* @param <T> table 泛型
* @author MUHUA
*/
@SuppressWarnings("unchecked")
public interface DataPermissionMapper<T> extends BaseMapper<T> {
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
@Override
@UserDataPermission
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
@Override
@UserDataPermission
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
使用自定义注解实现数据权限
最新推荐文章于 2024-05-22 20:00:00 发布