以下是关于Spring Security权限管理实现接口动态权限控制的完整攻略:
1. 什么是接口动态权限控制
接口动态权限控制即根据用户的权限动态的对接口进行权限控制,这个过程可以分为两步:一是获取用户所拥有的权限,二是根据用户所拥有的权限动态的对接口进行控制。
2. Spring Security实现接口动态权限控制的步骤
以下是实现Spring Security接口动态权限控制的步骤:
2.1 配置SecurityConfig
在SecurityConfig中,我们可以通过配置一个Bean来获取指定用户的权限信息。
@Bean
public UserDetailsService userDetailsService() {
return username -> {
// 这里是获取指定用户的权限信息
// 需要根据自己的业务逻辑来实现
};
}
2.2 实现AccessDecisionManager接口
AccessDecisionManager是Spring Security中的权限决策器,它用于决策当前用户是否有访问该接口的权限。在AccessDecisionManager中,我们需要获取当前用户的权限列表,并将其与当前接口需要的权限列表进行比较,从而得出用户是否有访问该接口的权限。
@Component
public class CustomAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
List<String> userAuthorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
List<String> requiredAuthorities = configAttributes.stream()
.map(ConfigAttribute::getAttribute)
.collect(Collectors.toList());
// 如果用户拥有该接口所需要的所有权限,则允许访问。
if (userAuthorities.containsAll(requiredAuthorities)) {
return;
}
throw new AccessDeniedException("无权限访问");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
2.3 配置SecurityMetadataSource
SecurityMetadataSource用于获取当前接口所需要的权限列表,在这里我们可以进行数据库或配置文件等方式的实现。
@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private final static Map<String, Collection<ConfigAttribute>> RESOURCE_ROLE_MAP = new ConcurrentHashMap<>();
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
HttpServletRequest request = fi.getHttpRequest();
String url = request.getRequestURI();
// 获取当前接口所需要的权限列表
Collection<ConfigAttribute> attributes = RESOURCE_ROLE_MAP.get(url);
if (attributes == null || attributes.isEmpty()) {
throw new AccessDeniedException("当前接口没有授权");
}
return attributes;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
/**
* 动态添加权限,可以通过数据库获取
* @param resourceRoleList
*/
public static void setResourceRoleList(List<ResourceRoleDO> resourceRoleList) {
resourceRoleList.forEach(resourceRoleDO -> {
ConfigAttribute configAttribute = new SecurityConfig(resourceRoleDO.getRoleCode());
if (RESOURCE_ROLE_MAP.containsKey(resourceRoleDO.getUrl())) {
RESOURCE_ROLE_MAP.get(resourceRoleDO.getUrl()).add(configAttribute);
} else {
Set<ConfigAttribute> configAttributes = new HashSet<>();
configAttributes.add(configAttribute);
RESOURCE_ROLE_MAP.put(resourceRoleDO.getUrl(), configAttributes);
}
});
}
}
2.4 配置FilterSecurityInterceptor
在FilterSecurityInterceptor中,我们需要设置AccessDecisionManager和SecurityMetadataSource。
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAccessDecisionManager customAccessDecisionManager;
@Autowired
private CustomSecurityMetadataSource customSecurityMetadataSource;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
// 设置不需要验证的接口
.antMatchers().permitAll()
// 设置所有接口都需要鉴权
.anyRequest().authenticated().and()
// 添加动态权限控制拦截器
.addFilterAfter(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
}
@Bean
public FilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource() {
return customSecurityMetadataSource;
}
@Bean
public CustomAccessDecisionManager customAccessDecisionManager() {
return customAccessDecisionManager;
}
/**
* 配置动态权限控制拦截器
* @return
*/
public DynamicFilterInvocationSecurityMetadataSource dynamicFilterInvocationSecurityMetadataSource() {
DynamicFilterInvocationSecurityMetadataSource dynamicFilterInvocationSecurityMetadataSource = new DynamicFilterInvocationSecurityMetadataSource();
dynamicFilterInvocationSecurityMetadataSource.setSecurityMetadataSource(customSecurityMetadataSource);
return dynamicFilterInvocationSecurityMetadataSource;
}
private FilterSecurityInterceptor dynamicSecurityFilter() {
FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
filterSecurityInterceptor.setSecurityMetadataSource(dynamicFilterInvocationSecurityMetadataSource());
filterSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager());
filterSecurityInterceptor.setObserveOncePerRequest(false);
return filterSecurityInterceptor;
}
}
以上就是Spring Security实现接口动态权限控制的完整攻略。
3. 示例说明
以下是两条示例说明:
3.1 动态添加权限
CustomSecurityMetadataSource.setResourceRoleList(resourceRoleList);
在这个方法中,我们通过查询数据库获取资源与角色的关系信息,并通过内存的方式动态的添加权限。
3.2 设置不需要验证的接口
在SecurityConfig中,我们可以通过设置不需要验证的接口,将这些接口开放出去,不需要进行权限控制。
http.csrf().disable().authorizeRequests()
.antMatchers().permitAll()
.anyRequest().authenticated().and()
.addFilterAfter(dynamicSecurityFilter(), FilterSecurityInterceptor.class);
通过.antMatchers().permitAll()方法设置不需要验证的接口。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security权限管理实现接口动态权限控制 - Python技术站