好的,这里简单举个例子,演示如何使用Spring Security实现基于角色的数据权限控制。
首先,在Spring Security中,可以使用@PreAuthorize注解来进行数据权限控制的配置。@PreAuthorize注解可以用于在方法调用之前对参数进行权限校验,如果权限校验不通过,则会抛出异常。
创建实体类和数据访问层
首先,我们创建一个User实体类和一个UserRepository数据访问层。User实体类中包含了一个username字段和一个departmentId字段,用于表示用户的账号名和所属部门。UserRepository数据访问层提供了一个findByDepartmentId方法,用于根据部门ID获取该部门下的所有用户信息。
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private Long departmentId;
// getters and setters
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByDepartmentId(Long departmentId);
}
创建服务层
接着,我们创建一个UserService服务层,用于提供用户信息的查询服务。在UserService服务层中,我们定义了一个getUsersByDepartmentId方法,该方法用于根据部门ID获取该部门下的所有用户信息。在方法中,我们首先获取当前登录用户的角色和部门信息,然后根据当前登录用户的角色和部门信息对返回的用户列表进行过滤,只返回符合条件的用户信息。
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private DepartmentService departmentService;
public List<User> getUsersByDepartmentId(Long departmentId) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentUsername = authentication.getName();
Set<String> currentRoles = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toSet());
Long currentDepartmentId = departmentService.getDepartmentIdByUsername(currentUsername);
List<User> users = userRepository.findByDepartmentId(departmentId);
if (!currentRoles.contains("ADMIN") && !Objects.equals(currentDepartmentId, departmentId)) {
users = users.stream()
.filter(user -> Objects.equals(user.getDepartmentId(), currentDepartmentId))
.collect(Collectors.toList());
}
return users;
}
}
创建控制器
最后,我们创建一个UserController控制器,用于提供用户信息查询的接口。在UserController控制器中,我们使用@PreAuthorize注解对接口进行权限控制的配置。只有拥有ADMIN角色或者对应用户具有读取权限的用户才能访问该接口。
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users/{departmentId}")
@PreAuthorize("hasRole('ADMIN') or hasPermission(#departmentId, 'read')")
public List<User> getUsers(@PathVariable Long departmentId) {
return userService.getUsersByDepartmentId(departmentId);
}
}
配置Spring Security
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private CustomPermissionEvaluator customPermissionEvaluator;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers(HttpMethod.GET, "/users/**").access("hasRole('ADMIN') or hasPermission(#departmentId, 'read')")
.antMatchers(HttpMethod.POST, "/users").access("hasRole('ADMIN') or hasPermission(#user.departmentId, 'write')")
.antMatchers(HttpMethod.PUT, "/users/**").access("hasRole('ADMIN') or hasPermission(#user.departmentId, 'write')")
.antMatchers(HttpMethod.DELETE, "/users/**").access("hasRole('ADMIN') or hasPermission(#user.departmentId, 'write')")
.and()
.formLogin()
.and()
.httpBasic()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
@Override
public void configure(WebSecurity web) throws Exception {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(customPermissionEvaluator);
web.expressionHandler(handler);
}
}
在SecurityConfig配置类中,我们使用了CustomUserDetailsService和CustomPermissionEvaluator两个自定义的服务。其中,CustomUserDetailsService用于加载用户信息,CustomPermissionEvaluator用于判断用户是否有指定权限。
自定义服务
最后,我们还需要实现CustomUserDetailsService和CustomPermissionEvaluator两个自定义服务。CustomUserDetailsService服务用于从数据库中加载用户信息。在CustomPermissionEvaluator服务中,我们实现了hasPermission方法,该方法用于判断当前用户是否有指定权限。
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + username));
List<SimpleGrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"));
return new org.springframework.security.core.userdetails.User(user.getUsername(), "", authorities);
}
}
@Service
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Autowired
private UserRepository userRepository;
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (targetDomainObject == null) {
return true;
}
Long departmentId = (Long) targetDomainObject;
User currentUser = userRepository.findByUsername(authentication.getName())
.orElseThrow(() -> new UsernameNotFoundException("User not found with username: " + authentication.getName()));
if (currentUser.getDepartmentId() == null) {
return false;
}
if ("read".equals(permission)) {
return currentUser.getDepartmentId().equals(departmentId) || "ADMIN".equals(authentication.getAuthorities().iterator().next().getAuthority());
} else if ("write".equals(permission)) {
return currentUser.getDepartmentId().equals(departmentId) || "ADMIN".