<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-freemarkerartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.securitygroupId>
<artifactId>spring-security-testartifactId>
<scope>testscope>
dependency>
dependencies>
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql:///ry?serverTimezone=Asia/Shanghai&useSSL=false
@SpringBootTest
class DataScopeApplicationTests {
@Test
void contextLoads() {
FastAutoGenerator.create("jdbc:mysql:///ry?serverTimezone=Asia/Shanghai&useSSL=false", "root", "123456")
.globalConfig(builder -> {
builder.author("fk") // 设置作者
.fileOverride() // 覆盖已生成文件
.outputDir("E:\\spring-boot-integration\\data-scope\\src\\main\\java"); // 指定输出目录
})
.packageConfig(builder -> {
builder.parent("com.kun.ds") // 设置父包名
.pathInfo(Collections.singletonMap(OutputFile.xml, "E:\\spring-boot-integration\\data-scope\\src\\main\\resources\\mapper\\")); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude("sys_dept","sys_role","sys_user") // 设置需要生成的表名
.addTablePrefix("sys_"); // 设置过滤表前缀
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
.execute();
}
}
@TableName("sys_user")
public class User implements Serializable, UserDetails {
....前边省略实体类原有部分.....
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(User::getUsername,username);
User user = getOne(wrapper);
if (user == null){
throw new UsernameNotFoundException("用户不存在!");
}
return user;
}
}
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
IDeptService deptService;
@GetMapping("/")
public List<Dept> getAllDepts(){
return deptService.list();
}
}
public class BaseEntity {
@TableField(exist = false)
private Map<String,String> params = new HashMap<>();
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}
让所以的实体类继承上边的BaseEntity
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataScope {
//别名
String deptAlias() default "";
String userAlias() default "";
}
因为要根据用户角色生成SQL,所以先给USER实体类添加roles属性,在service中设置角色,以便切面使用
//实体类添加修改部分
@TableField(exist = false)
@JsonIgnore
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream().map(r -> new SimpleGrantedAuthority(r.getRoleKey())).collect(Collectors.toList());
}
//service修改
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {
@Autowired
UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.lambda().eq(User::getUserName, username);
User user = getOne(qw);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
user.setRoles(userMapper.getRolesByUid(user.getUserId()));
return user;
}
}
<select id="getRolesByUid" resultType="com.kun.ds.entity.Role">
select r.* from sys_role r,sys_user_role ur where r.role_id=ur.role_id and ur.user_id=#{userId}
select>
下边是切面类代码,详见注释:
@Aspect
@Component
public class DataScopeAspect {
//权限的分类
public static final String DATA_SCOPE_ALL = "1";//查所有
public static final String DATA_SCOPE_CUSTOM = "2";//表中自定义
public static final String DATA_SCOPE_DEPT = "3";//本部门
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";//本部门及子部门
public static final String DATA_SCOPE_SELF = "5";//只能看自己
public static final String DATA_SCOPE = "data_scope";//param的key
@Before("@annotation(dataScope)")
public void doBefore(JoinPoint jp, DataScope dataScope){
//防止SQL注入
clearDataScope(jp);
//获取当前用户信息
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//超级管理员,不需要权限过滤
if (user.getUserId() == 1L){
return;
}
//其他权限生成过滤sql语句
StringBuilder sql = new StringBuilder();
List<Role> roles = user.getRoles();
//select * from sys_dept d where d.del_flag='0' and (xxx OR xxx OR xxx)
//d.dept_id in(select rd.dept_id from sys_user_role ur,sys_role_dept rd where ur.user_id=2 and ur.role_id=rd.role_id) 代表一个 xxx
for (Role role:roles){
String ds = role.getDataScope();
//循环遍历角色根据权限生成sql
if (DATA_SCOPE_ALL.equals(ds)) {
//如果用户能够查看所有数据,这里什么都用不做
return;
} else if (DATA_SCOPE_CUSTOM.equals(ds)) {
//自定义的数据权限,那么就根据 用户角色去查找到部门 id
sql.append(String.format(" OR %s.dept_id in(select rd.dept_id from sys_role_dept rd where rd.role_id=%d)", dataScope.deptAlias(), role.getRoleId()));
} else if (DATA_SCOPE_DEPT.equals(ds)) {
//只看自己的部门
sql.append(String.format(" OR %s.dept_id=%d", dataScope.deptAlias(), user.getDeptId()));
} else if (DATA_SCOPE_DEPT_AND_CHILD.equals(ds)) {
//自己部门和子部门
sql.append(String.format(" OR %s.dept_id in(select dept_id from sys_dept where dept_id=%d or find_in_set(%d,`ancestors`))", dataScope.deptAlias(), user.getDeptId(), user.getDeptId()));
} else if (DATA_SCOPE_SELF.equals(ds)) {
//只能看自己
String s = dataScope.userAlias();
if ("".equals(s)) {
//数据权限仅限于本人
sql.append(" OR 1=0");
} else {
sql.append(String.format(" OR %s.user_id=%d", dataScope.userAlias(), user.getUserId()));
}
}
}
//and(xxx or xxx)
Object arg = jp.getArgs()[0];
if (arg != null && arg instanceof BaseEntity){
BaseEntity baseEntity = (BaseEntity) arg;
baseEntity.getParams().put(DATA_SCOPE," AND ("+sql.substring(4)+")");
}
}
/**
* 如果params中已经有参数,则删掉
* @param jp
*/
private void clearDataScope(JoinPoint jp) {
Object arg = jp.getArgs()[0];
if (arg != null && arg instanceof BaseEntity){
BaseEntity baseEntity = (BaseEntity) arg;
baseEntity.getParams().put(DATA_SCOPE,"");
}
}
}
修改刚才的测试接口,传入参数
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
IDeptService deptService;
@GetMapping("/")
public List<Dept> getAllDepts(Dept dept){
return deptService.getAllDepts(dept);
}
}
//service
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
@Autowired
DeptMapper deptMapper;
@Override
@DataScope(deptAlias = "d")
public List<Dept> getAllDepts(Dept dept) {
return deptMapper.getAllDepts(dept);
}
}
<select id="getAllDepts" resultType="com.kun.ds.entity.Dept">
select * from sys_dept d where d.del_flag='0'
${params.data_scope}
select>