<groupId>org.example</groupId>
<artifactId>spring-mybatis-source</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.5</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-cache</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="100"/>
<property name="maxIdle" value="30"/>
<property name="maxWait" value="500"/>
<property name="defaultAutoCommit" value="true"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.lmh.dao.UserMapper"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="User" type="com.lmh.entity.User"/>
</typeAliases>
<plugins>
<plugin interceptor="com.lmh.interceptor.PrivilegeExecutorInterceptor"/>
</plugins>
<mappers>
<mapper resource="dao/UserMapper.xml"/>
</mappers>
</configuration>
package com.lmh.entity;
private Long id;
private String username;
private String password;
private String email;
private String headImage;
private String countryName;
// ...get set
import com.lmh.entity.User;
public interface UserMapper {
User findUserById(@Param("password") String password);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lmh.dao.UserMapper">
<select id="findUserById" resultType="User">
select
id id,
user_name username,
user_password password,
user_email email,
head_image headImage,
country_name countryName
from sys_user where user_password = #{password}
<![CDATA[
<addAuth joiner = 'and' columnName = 'country_name' symbol = 'in' privilegeDimension='country'/>
]]>
</select>
</mapper>
@Intercepts(
@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
)
public class PrivilegeExecutorInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
//获取executor对象
Executor executor = (Executor)invocation.getTarget();
//获取到mappedStatement
MappedStatement ms = (MappedStatement)invocation.getArgs()[0];
//查询参数
Object parameterObject = invocation.getArgs()[1];
//获取boundSql
BoundSql boundSql = ms.getBoundSql(parameterObject);
String sql = boundSql.getSql();
if (sql.contains(")) {
sql = AddAuthParser.parse(sql);
}
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), parameterObject);
//这里没有使用缓存
return executor.query(ms, parameterObject, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER, null, newBoundSql);
}
/**
* 注册拦截器
*/
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
public class CountryPrivilegeInfo {
/**
* and、or
*/
private String joiner = "and";
/**
* in、not in、 = 、<>等等
* 这里案例只用 in
*/
private String symbol = "in";
/**
* 数据库列名
*/
private String columnName;
/**
* 权限维度。案例用的是country维度
*/
private String privilegeDimension;
/**
* 用户上下文的值。实际工作中从登陆上下文中获取
*/
private List<String> rolePrivileges = getCountryFromContext();
public CountryPrivilegeInfo(String joiner, String symbol, String columnName, String privilegeDimension) {
this.joiner = joiner;
this.symbol = symbol;
this.columnName = columnName;
this.privilegeDimension = privilegeDimension;
}
/**
* 获取用户所管理的国家信息
*/
private List<String> getCountryFromContext() {
List<String> list = new ArrayList<>();
list.add("cn");
list.add("us");
return list;
}
}
//省略 get set
public class AddAuthParser {
/**
* 暂时不考虑有多个标签的情况
*/
public static String parse(String sql) {
StringBuilder finalSql = new StringBuilder();
String[] preSplit = sql.split(");
String preSql = preSplit[1];
String addAuthSql = preSql.substring(0, preSql.indexOf("/>"));
String suffixSql = preSql.substring(preSql.indexOf("/>") + "/>".length());
return finalSql.append(preSplit[0]).
append(doParseAddAuthSql(addAuthSql)).
append(suffixSql).toString();
}
/**
* 解析标签里面的内容
*/
private static String doParseAddAuthSql(String sql) {
//数据权限维度。实例工作中为地区、数据角色等维度
String privilegeDimension = getValueByProperty("privilegeDimension", sql);
String columnName = getValueByProperty("columnName", sql);
String symbol = getValueByProperty("symbol", sql);
String joiner = getValueByProperty("joiner", sql);
CountryPrivilegeInfo countryPrivilegeInfo = new CountryPrivilegeInfo(joiner, symbol, columnName, privilegeDimension);
StringBuilder privilegeStr = new StringBuilder(" ( ");
List<String> rolePrivileges = countryPrivilegeInfo.getRolePrivileges();
for (int i = 0; i < rolePrivileges.size(); i++) {
privilegeStr.append("'").append(rolePrivileges.get(i)).append("'");
if (i < rolePrivileges.size() - 1) {
privilegeStr.append(", ");
}
}
privilegeStr.append(" ) ");
return " " + joiner + " "+ columnName + " "+ symbol + " " +privilegeStr;
}
private static String getValueByProperty(String property, String sql) {
sql = sql.replace(" ", "");
String open = property + "='";
String close = "'";
String[] split = sql.split(open);
String value = split[1].substring(0, split[1].indexOf(close));
return value.trim();
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
UserMapper userMapper = (UserMapper)context.getBean("userMapper");
User userById = userMapper.findUserById("123456");
System.out.println("userById = " + userById);
}
UserMapper.findUserById - ==> Preparing: select id id, user_name username, user_password password, user_email email, head_image headImage, country_name countryName from sys_user where user_password = ? and country_name in ( 'cn', 'us' )
UserMapper.findUserById - ==> Parameters: 123456(String)
这样就实现了加上一个标签,就对登陆用户的数据权限进行了过滤
<![CDATA[
<addAuth joiner = 'and' columnName = 'country_name' symbol = 'in' privilegeDimension='country'/>
]]>