史上最简单的Spring Security教程(二十):AccessDecisionVoter必须全部拥有请求所需权限才可访问
前面我们说了 AccessDecisionVoter 的一些基本用法,以及常用的一些 AccessDecisionVoter 实现,当然,也试着自定义了一个 AccessDecisionVoter。
细心的同学可能有所发现,这个自定义的 AccessDecisionVoter 不寻常。为什么呢?因为它内部的授权决策逻辑刚好就是必须拥有当前请求所需的全部权限才会授权成功。同时,这也是这次我们要着重说的内容。
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
https://github.com/liuminglei/SpringSecurityLearning/tree/master/20
gitee
https://gitee.com/xbd521/SpringSecurityLearning/tree/master/20
回复以下关键字,获取更多资源
SpringCloud进阶之路 | Java 基础 | 微服务 | JAVA WEB | JAVA 进阶 | JAVA 面试 | MK 精讲
笔者开通了个人微信公众号【银河架构师】,分享工作、生活过程中的心得体会,填坑指南,技术感悟等内容,会比博客提前更新,欢迎订阅。
技术资料领取方法:关注公众号,回复微服务,领取微服务相关电子书;回复MK精讲,领取MK精讲系列电子书;回复JAVA 进阶,领取JAVA进阶知识相关电子书;回复JAVA面试,领取JAVA面试相关电子书,回复JAVA WEB领取JAVA WEB相关电子书。