SpringBoot 动态权限、动态SQL功能实现

动态权限表设计思路:

用户对角色、角色对接口和自定义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>

这样就行了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值