前面我们说了 AccessDecisionVoter 的一些基本用法,以及常用的一些 AccessDecisionVoter 实现,当然,也试着自定义了一个 AccessDecisionVoter。
细心的同学可能有所发现,这个自定义的 AccessDecisionVoter 不寻常。为什么呢?因为它内部的授权决策逻辑刚好就是必须拥有当前请求所需的全部权限才会授权成功。同时,这也是这次我们要着重说的内容。
@Override
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED;
}
int result = ACCESS_ABSTAIN;
Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
// Attempt to find all matching granted authority
for (GrantedAuthority authority : authorities) {
if (attribute.getAttribute().equals(authority.getAuthority())) {
result = ACCESS_GRANTED;
break;
}
}
if (result == ACCESS_DENIED) {
return ACCESS_DENIED;
}
}
}
return result;
}
从代码逻辑中不难判断,只要所需权限,任意一个不再用户授权范围内,即会授权失败。既然如此,那么我们就尝试一下吧。
首先,定义一个新的角色 User_2。
INSERT INTO SYS_ROLE(`ID`, `NAME`, `CODE`) VALUES ('617fe676082c40e0a06b9a9646cfb1e7', '普通用户', 'User_2');
然后,将 User_2 角色与 个人中心功能(/user/index)关联起来,即分配个人中心资源权限给 User_2
INSERT INTO SYS_ROLE_FUNC(`ID`, `ROLE_ID`, `FUNC_ID`) VALUES ('83f1e68a08ac4e1b9b5cd45628f64235', '617fe676082c40e0a06b9a9646cfb1e7', '8fc7c56295e542aaa436c4dbf0048578');
如此一来,个人中心就需要用户同时拥有 User 和 User_2
最后,修改一下 Spring Security 的配置,将自定义的 AccessDecisionVoter 配置到 AccessDecisionManager
private AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> voters = new ArrayList<>();
voters.add(new AllMatchRoleVoter());
return new AffirmativeBased(voters);
}
准备工作就绪,我们启动系统,访问个人中心。登录后,果然跳转到了无权限页面。
初步验证成功,我们此时再分配 User_2 角色给 zhangsan
INSERT INTO SYS_USER_ROLE(`ID`, `USER_ID`, `ROLE_ID`) VALUES ('a27108d05c5843bf92eed3ae47ef4220', '2031a4adc78942d59188cea7927e6304', '617fe676082c40e0a06b9a9646cfb1e7');
不用重启系统,我们先访问一下首页(/index)。然后,点击右上角 退出登录
注意,为何我们需要先访问一下首页(/index),然后退出登录,再重新登录一次呢(当然,也可以直接访问退出登录页面 /logout,如果你配置的是这个路径的话)?其实,只要你细心,便不难发现个中缘由。
用户的权限正是在系统登录时,由配置的 UserDetailsService 获取,中途只要不退出系统,便不会再次主动去获取。因此,需要我们退出系统,重新登录一次,才能获取最新分配的权限。当然,重启系统肯定也可以,不过没有必要。
其它详细源码,请参考文末源码链接,可自行下载后阅读。
源码
github
liuminglei/SpringSecurityLearning
gitee
luas/SpringSecurityLearning
我是银河架构师,十年饮冰,难凉热血,愿历尽千帆,归来仍是少年!