数据库有三张表 menu(菜单表) 、 menu_role 和 role(角色表)
url字段存放该菜单下的所有请求的一个通用形式,用于后面匹配请求是哪一个菜单
menu_role表连接menu表和role表
角色表
name为权限名
动态权限判定原理:
查询每一个资源的所有权限,拦截request,将requestUrl与资源url匹配 将匹配到的资源对应的所有权限存入SpringSecurity管理 未匹配到的资源,默认为登录即可访问的资源 制定决策,获取当前登录用户,将用户的权限集合与之前存储的访问资源 的权限集合进行匹配,如果有交集就说明当前用户拥有权限访问该资源
实现过程:
查询所有资源及其权限
@Component
public class CustomFilter implements FilterInvocationSecuritymetadataSource {
@Autowired
private IMenuService menuService;
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Collection getAttributes(Object o) throws IllegalArgumentException {
//获取请求的url
String requestUrl = ((FilterInvocation) o).getRequestUrl();
//查询出来了每一个菜单及其对应所需要的角色
List
制定决策
@Component
public class CustomUrlDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object o, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException {
//遍历权限集合
for (ConfigAttribute configAttribute : collection) {
//当前url所需要的权限
String needRole = configAttribute.getAttribute();
//判断是否是登录即可访问的角色,此角色在CustomFilter中设置
if ("ROLE_LOGIN".equalsIgnoreCase(needRole)) {
//判断是否登录
if (authentication instanceof AnonymousAuthenticationToken) {
throw new AccessDeniedException("尚未登录,请登录!");
} else {
return;
}
}
//判断用户权限是否为url所需权限
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 false;
}
@Override
public boolean supports(Class> aClass) {
return false;
}
}
SecurityConfig配置
//动态权限配置
http.withObjectPostProcessor(new ObjectPostProcessor() {
@Override
public O postProcess(O object) {
object.setAccessDecisionManager(customUrlDecisionManager);
object.setSecuritymetadataSource(customFilter);
return object;
}
})
注意
用户登录时,不仅要查询用户基本信息,还需要查询拥有的权限信息 查询的所有权限需要封装成UserDetails指定的的权限集合
@Override
public Collection extends GrantedAuthority> getAuthorities() {
//map就是一个加工方法,将stream中的每一个元素按照一定规则加工
//collect就是能将stream转换为集合
List authorities = roles
.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
return authorities;
}



