问题描述:FilterInvocationSecurityMetadataSource 下的 getAttributes(Object o)方法执行完后不走AccessDecisionManager的实现类
解决办法:
getAttributes 方法返回一个 无权限,而不是返回null
Collection<ConfigAttribute> collection = new LinkedList<>();
//防止数据库中没有数据,不能进行权限拦截
if(collection.size() < 1){
ConfigAttribute configAttribute = new SecurityConfig("ROLE_NO_USER");
collection.add(configAttribute);
}
return collection;
附完整动态权限代码如下:
/**
* @author lyy
* 加载请求需要的角色
*/
@Component
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Resource
private AuthorityMapper authorityMapper;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
/**
* 目的返回当前请求所需要的角色数组
* @param o
* @return
* @throws IllegalArgumentException
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
//获取请求地址
String requestUrl = ((FilterInvocation) o).getRequestUrl();
// 获取表 hs_authority 里字段authority_sys_url不为空的数据
List<Authority> allMenu = authorityMapper.getAllMenu();
for (Authority mwMenu : allMenu) {
if (antPathMatcher.match(mwMenu.getAuthoritySysUrl(), requestUrl) && mwMenu.getRoles().size() > 0) {
ArrayList<String> strings = new ArrayList<>();
// 获取该接口的所有角色 add 到strings
mwMenu.getRoles().forEach(
oo -> strings.add(oo.getRoleCode())
);
List<String> collect = strings.stream().distinct().collect(Collectors.toList());
if (collect.size() == 0){
return null;
}else {
return SecurityConfig.createList(collect.toArray(new String[collect.size()]));
}
}
}
Collection<ConfigAttribute> collection = new LinkedList<>();
//防止数据库中没有数据,不能进行权限拦截
if(collection.size() < 1){
ConfigAttribute configAttribute = new SecurityConfig("ROLE_NO_USER");
collection.add(configAttribute);
}
return collection;
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}
/**
* 权限认证
*/
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, AuthenticationException {
for (ConfigAttribute ca : collection) {
//当前请求需要的权限
String needRole = ca.getAttribute();
if (authentication instanceof AnonymousAuthenticationToken) {
throw new BadCredentialsException("未登录");
}
//当前用户所具有的权限
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(needRole)) {
return;
}
}
}
throw new AccessDeniedException("权限不足!");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启注解@PreAuthorize/@PostAuthorize
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
UserLoginServiceImpl userLoginService;
@Resource
UrlFilterInvocationSecurityMetadataSource urlFilterInvocationSecurityMetadataSource;
@Resource
UrlAccessDecisionManager urlAccessDecisionManager;
@Resource
AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;
@Resource
private RedisUtils redisUtils;
private String[] SWAGGER_WHITELIST = {
"/refreshRedisDict",
"/getDictList",
"/getDictByCode",
"/userLogout",
"/userLogin",
"/getAllMenu",
"/oss/uploadFile",
"/judge/**"
};
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userLoginService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(SWAGGER_WHITELIST);;
}
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 所有的rest服务一定要设置为无状态,以提升操作效率和性能
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
// 所有请求都需要经过验证
.and().authorizeRequests()
.withObjectPostProcessor(
new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
o.setSecurityMetadataSource(urlFilterInvocationSecurityMetadataSource);
o.setAccessDecisionManager(urlAccessDecisionManager);
return o;
}
})
.and().formLogin().loginPage("/login/warning").usernameParameter("username").passwordParameter("password").permitAll()
// 添加过滤器
.and().addFilter(new JWTAuthenticationFilter(authenticationManager(),userLoginService,redisUtils))
// 退出登录
.logout().permitAll()
.and().cors()
.and().csrf().disable().exceptionHandling().accessDeniedHandler(authenticationAccessDeniedHandler);
}
}