Spring Boot 3 项目整合DataPermissionInterceptor 实现数据权限

创建注解类

package com.dnk.business.link.annotation;

import com.dnk.business.link.web.system.enums.DataPermissionTypeEnum;

import java.lang.annotation.*;

/**
 * 数据权限注解
 * 用于MyBatis Mapper方法上,配合DataPermissionInterceptor实现数据权限过滤
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataPermission {

    /**
     * 数据权限类型
     */
    DataPermissionTypeEnum type();

    /**
     * SQL中的表别名,默认为空
     */
    String alias() default "";

    /**
     * 不过滤的字段。例如某个字段为某个值表示全部可见的时候需要配置unfilteredField和unfilteredValue
     */
    String unfilteredField() default "";

    /**
     * 不过滤的值
     */
    String unfilteredValue() default "";
}

实现DataPermissionHandler

package com.dnk.config.mp;

import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.dnk.business.link.annotation.DataPermission;
import com.dnk.business.link.util.TokenUserInfo;
import com.dnk.business.link.web.system.entity.SysUser;
import com.dnk.business.link.web.system.enums.DataPermissionTypeEnum;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.reflect.Method;

/**
 * 数据权限处理器
 */
@Slf4j
@Component
public class MyDataPermissionHandler implements DataPermissionHandler {

    @Autowired
    private HttpServletRequest request;

    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        try {
            // 获取Mapper方法上的注解
            String className = mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."));
            String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
            
            Class<?> mapperClass = Class.forName(className);
            Method[] methods = mapperClass.getMethods();
            DataPermission dataPermission = null;
            
            // 简单匹配方法名,暂不考虑重载情况(MyBatis Mapper通常不建议重载)
            for (Method method : methods) {
                if (method.getName().equals(methodName) && method.isAnnotationPresent(DataPermission.class)) {
                    dataPermission = method.getAnnotation(DataPermission.class);
                    break;
                }
            }

            if (dataPermission == null) {
                return where;
            }

            // 获取当前用户
            // 注意:这里可能在非Web环境下调用,需要判空
            if (RequestContextHolder.getRequestAttributes() == null) {
                return where;
            }
            SysUser user = TokenUserInfo.getTokenUserInfo(request);
            if (user == null) {
                // 未登录,不返回数据
                return CCJSqlParserUtil.parseCondExpression("1=0");
            }
            
            // 管理员查看所有数据
            if ("1".equals(user.getUserType())) {
                return where;
            }

            // 构造权限SQL
            DataPermissionTypeEnum type = dataPermission.type();
            String alias = dataPermission.alias();
            String tableName = StringUtils.isNotBlank(alias) ? alias : type.getTableName();

            // 处理别名
            String dataIdColumn = tableName + ".id";

            // 处理不过滤的条件(如果有)
            String unfilteredSql = null;
            if (StringUtils.isNotBlank(dataPermission.unfilteredField())) {
                unfilteredSql = tableName + ". " +dataPermission.unfilteredField() + " = '" + dataPermission.unfilteredValue() + "'";

            }

            // 构造权限SQL
            String sql = String.format(
                    "(exists (select 1 from sys_data_permission p join sys_dept_user_rel u on p.dept_id = u.dept_id where p.data_id = %s and p.data_type = '%s' and u.user_id = %s) %s)",
                    dataIdColumn, type.getCode(), user.getId(), StringUtils.isNotBlank(unfilteredSql) ? "or " + unfilteredSql : ""
            );

            Expression appendExpression = CCJSqlParserUtil.parseCondExpression(sql);
            // 拼接 AND 条件
            AndExpression andExpression = new AndExpression(where, appendExpression);
            log.debug("附加数据权限SQL: {}", andExpression.toString());
            return andExpression;

        } catch (Exception e) {
            log.error("数据权限处理异常", e);
            // 异常时为了安全起见,可以不返回数据或者忽略
            return null;
        }
    }
}

数据类型枚举

package com.dnk.business.link.web.system.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 数据权限类型枚举
 */
@Getter
@AllArgsConstructor
public enum DataPermissionTypeEnum {


    /**
     * AI提示词信息
     */
    PROMPT("prompt", "ai_prompt", "AI提示词信息"),
    ;

    /**
     * 类型编码(前端传递)
     */
    private final String code;

    /**
     * 数据库表名
     */
    private final String tableName;

    /**
     * 描述
     */
    private final String description;

    /**
     * 根据编码获取表名
     *
     * @param code 类型编码
     * @return 表名
     */
    public static String getTableNameByCode(String code) {
        for (DataPermissionTypeEnum value : values()) {
            if (value.getCode().equals(code)) {
                return value.getTableName();
            }
        }
        return null;
    }

    /**
     * 校验编码是否存在
     *
     * @param code 类型编码
     * @return 是否存在
     */
    public static boolean isValidCode(String code) {
        for (DataPermissionTypeEnum value : values()) {
            if (value.getCode().equals(code)) {
                return true;
            }
        }
        return false;
    }
}

上述仅为示例,具体以实际业务进行改造。

用法:在Mapper方法中添加注解

@DataPermission(type = DataPermissionTypeEnum.PROMPT, alias = "ap", unfilteredField = "sys_dept_id", unfilteredValue = "0")
    List<AiPrompt> queryByAiModelSetting(QueryAiPromptQo queryAiPromptQo);

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇