动态权限表设计思路:
用户对角色、角色对接口和自定义SQL的配置。
定义一个DataScope注解
/**
* 数据权限过滤注解
*
*/
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
//内部暂时不需要参数,只是用这个注解用来做AOP的监控
}
给要加权限的接口加上注解
写一个AOP监控类,主要思路:
监控在需要验证权限的方法进来后,在调用数据库逻辑之前,手动获取数据的动态SQL,拼接到请求参数里面,最后把这个参数写到sql里面就行了
package com.java.core.web.aop;
import com.java.core.com.utils.StringUtils;
import com.java.core.com.utils.spring.SpringUtils;
import com.java.core.core.security.JwtTokenUtils;
import com.java.core.entity.master.BaseEntity;
import com.java.core.entity.master.SysRule;
import com.java.core.entity.master.SysUser;
import com.java.core.mapper.master.SysRuleMapper;
import com.java.core.service.system.SysUserService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
/**
* 数据过滤处理
*
*/
@Aspect
@Component
public class DataScopeAspect {
/**
* 数据权限过滤关键字
*/
public static final String DATA_SCOPE = "dataScope";
// 配置织入点
@Pointcut("@annotation(com.java.core.com.annotation.DataScope)")
public void pointcut()
{
}
/**
* 请求前访问
*
* @param joinPoint 切点
*/
@Before("pointcut()")
public void beforeAdvice(JoinPoint joinPoint) throws Exception {
try {
clearDataScope(joinPoint);
dataScope(joinPoint);
}catch (Exception e){
throw new Exception("Aop DataScope Error:"+e.getMessage());
}
}
protected void dataScope(final JoinPoint joinPoint)
{
// 获取当前的用户
String userId = JwtTokenUtils.getUserId();
SysUser user = SpringUtils.getBean(SysUserService.class).selectById(Long.parseLong(userId));
if(user==null)return;//找不到用户不处理
if(user.isAdmin())return;//超级管理员,则不过滤数据,因为加权限的sql都是不带w
//动态权限SQL拼接
dataScopeFilter(joinPoint, user);
}
/**
* 数据范围过滤
*
* @param joinPoint 切点
* @param user 用户
*/
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user)
{
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//请求的地址
String apiUrl = request.getRequestURI();
StringBuilder sqlString = new StringBuilder();
List<SysRule> ruleList = SpringUtils.getBean(SysRuleMapper.class).getDataScope(user.getUser_id(),apiUrl);
if(ruleList.size()==0)return;//找不到权限不处理
//符合条件的全部用or拼接起来
for (SysRule rule:ruleList) {
String sql=rule.getSql();
//字符变量替换
//sql=sql.replace("#{userId}",user.getUser_id())
sqlString.append(sql+" or");
}
//拼接一个完整的条件
sqlString.append(" 1=0");
//动态SQL写入请求参数
if (StringUtils.isNotBlank(sqlString.toString()))
{
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString + ")");
}
}
}
/**
* 拼接权限sql前先清空params.dataScope参数防止注入
*/
private void clearDataScope(final JoinPoint joinPoint)
{
Object params = joinPoint.getArgs()[0];
if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
if(baseEntity.getParams()==null){
baseEntity.setParams(new HashMap<String, Object>());
}
baseEntity.getParams().put(DATA_SCOPE, "");
}
}
}
Mybatis写法
<select id="dynamicSqlTest" resultType="com.java.core.entity.master.SysUser">
SELECT * FROM sys_user
WHERE 1=1
<!-- 数据范围过滤 -->
${params.dataScope}
</select>
这样就行了