springbootsecurity动态权限
时间: 2023-11-16 14:50:31 浏览: 45
Spring Boot Security提供了动态权限管理的支持,可以在运行时动态地添加、修改和删除用户权限,而无需重新启动应用程序。以下是实现动态权限的步骤:
1. 配置Spring Security
在Spring Security配置类中,需要指定权限管理器和访问决策管理器:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private CustomPermissionEvaluator permissionEvaluator;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.accessDecisionManager(accessDecisionManager())
.and()
.formLogin()
.and()
.httpBasic()
.and()
.csrf().disable();
}
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
@Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList(
new WebExpressionVoter(),
new RoleVoter(),
new AuthenticatedVoter(),
new CustomPermissionVoter(permissionEvaluator)
);
return new AffirmativeBased(decisionVoters);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
```
2. 实现自定义权限管理器和访问决策管理器
自定义权限管理器和访问决策管理器是实现动态权限管理的关键。权限管理器负责加载用户权限,访问决策管理器负责根据用户权限决策是否允许访问某个资源。
```
@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
@Autowired
private PermissionService permissionService;
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
if (authentication == null || targetDomainObject == null || !(permission instanceof String)) {
return false;
}
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
String targetType = targetDomainObject.getClass().getSimpleName().toUpperCase();
PermissionType permissionType = PermissionType.valueOf((String) permission);
return permissionService.hasPermission(userDetails.getUserId(), targetType, permissionType);
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
if (authentication == null || targetType == null || !(permission instanceof String)) {
return false;
}
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
PermissionType permissionType = PermissionType.valueOf((String) permission);
return permissionService.hasPermission(userDetails.getUserId(), targetType.toUpperCase(), permissionType);
}
}
@Component
public class CustomPermissionVoter extends AbstractAccessDecisionVoter<Object> {
private final PermissionEvaluator permissionEvaluator;
public CustomPermissionVoter(PermissionEvaluator permissionEvaluator) {
super("ROLE_USER");
this.permissionEvaluator = permissionEvaluator;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return attribute.getAttribute() != null && attribute.getAttribute().startsWith("PERM_");
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
@Override
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
int result = ACCESS_ABSTAIN;
CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
String permission = attribute.getAttribute().substring(5);
Object targetObject = object;
if (object instanceof FilterInvocation) {
FilterInvocation filterInvocation = (FilterInvocation) object;
HttpServletRequest request = filterInvocation.getRequest();
targetObject = new CustomWebSecurityExpressionRoot(authentication, request);
}
if (permissionEvaluator.hasPermission(authentication, targetObject, permission)) {
return ACCESS_GRANTED;
}
}
}
return result;
}
}
```
3. 实现自定义用户权限加载器
自定义用户权限加载器负责从数据库或其他数据源中加载用户权限,可以在运行时动态地添加、修改和删除用户权限。
```
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private PermissionService permissionService;
@Override
public CustomUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
List<Permission> permissions = permissionService.getPermissionsByUserId(user.getId());
Set<GrantedAuthority> authorities = new HashSet<>();
for (Permission permission : permissions) {
authorities.add(new SimpleGrantedAuthority("PERM_" + permission.getPermissionType()));
}
return new CustomUserDetails(user.getId(), user.getUsername(), user.getPassword(), authorities);
}
}
```
4. 实现自定义权限管理器
自定义权限管理器负责将用户权限加载到Spring Security的安全上下文中。
```
@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private final Map<String, Collection<ConfigAttribute>> resourceMap = new ConcurrentHashMap<>();
@Autowired
private PermissionService permissionService;
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
if (object instanceof FilterInvocation) {
FilterInvocation filterInvocation = (FilterInvocation) object;
HttpServletRequest request = filterInvocation.getRequest();
String url = request.getRequestURI();
String method = request.getMethod();
String key = url + ":" + method;
if (resourceMap.containsKey(key)) {
return resourceMap.get(key);
} else {
List<Permission> permissions = permissionService.getPermissionsByUrlAndMethod(url, method);
Collection<ConfigAttribute> configAttributes = new HashSet<>();
for (Permission permission : permissions) {
configAttributes.add(new SecurityConfig("PERM_" + permission.getPermissionType()));
}
resourceMap.put(key, configAttributes);
return configAttributes;
}
}
return null;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
```
5. 实现自定义权限服务
自定义权限服务负责提供添加、修改和删除用户权限的接口。
```
@Service
public class PermissionService {
@Autowired
private PermissionRepository permissionRepository;
public List<Permission> getPermissionsByUserId(Long userId) {
return permissionRepository.findByUserId(userId);
}
public List<Permission> getPermissionsByUrlAndMethod(String url, String method) {
return permissionRepository.findByUrlAndMethod(url, method);
}
public boolean hasPermission(Long userId, String targetType, PermissionType permissionType) {
List<Permission> permissions = permissionRepository.findByUserIdAndTargetTypeAndPermissionType(userId, targetType, permissionType);
return !permissions.isEmpty();
}
public void addPermission(Permission permission) {
permissionRepository.save(permission);
}
public void updatePermission(Permission permission) {
permissionRepository.save(permission);
}
public void deletePermission(Long permissionId) {
permissionRepository.deleteById(permissionId);
}
}
```
6. 在运行时动态添加、修改和删除用户权限
在需要添加、修改和删除用户权限的地方,调用自定义权限服务的接口即可。
例如,可以实现一个RESTful API,用于添加、修改和删除用户权限:
```
@RestController
@RequestMapping("/permissions")
public class PermissionController {
@Autowired
private PermissionService permissionService;
@PostMapping
public void addPermission(@RequestBody Permission permission) {
permissionService.addPermission(permission);
}
@PutMapping("/{id}")
public void updatePermission(@PathVariable Long id, @RequestBody Permission permission) {
permission.setId(id);
permissionService.updatePermission(permission);
}
@DeleteMapping("/{id}")
public void deletePermission(@PathVariable Long id) {
permissionService.deletePermission(id);
}
}
```