spring-security,有没有对需要权限控制的 url 存入数据库的实现。
以前一个项目,客户要求实现自己 一套颗粒度很细的权限管理,自己可以编辑配置。实现过程要花点时间,难度不大,全部( API 的 URLPattern,HTTPMETHOD,一条不同操作对应一条授权 Permission )保存到数据库,用户页面可以打开授权,整页面都是 CheckBox 的 Permissions,客户看到那个后自己都晕了,感觉自己蠢了。
<http>
<intercept-url pattern=”/user/**”
access=”@webSecurity.check(authentication,request)”/>
…
</http>
or in Java configuration
http
.authorizeRequests(authorize -> authorize
.antMatchers(“/user/**”).access(“@webSecurity.check(authentication,request)”)
…
)
`
Reactive 应用就更简单
`
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.pathMatchers(“/api/**”).access(customerAccessCheck)
…
return http.build();
}
`
private String url;
@ElementCollection
private List<Long> uIds;
}
// —– 控制层 @PreAuthorize(“@userProfileManager.currentUserAuthForUlr(authentication,httpServletRequest.requestURL.toString())”)
@PutMapping(“password”)
public ResponseEntity<String> changePassword(@RequestParam String newPassword, Authentication authentication) {
profileManager.changePassword(newPassword, authentication);
return ResponseEntity.ok(“success”);
}
// ——– service
public class UserProfileManager {
// 各种注入
public boolean currentUserAuthForUlr(Authentication authentication, String url) {
Optional<UserProfile> optional = userProfileMapper.findOne(Example.of(new UserProfile().setEmail(authentication.getPrincipal().toString())));
UserProfile profile = optional.orElseThrow(() -> new BadCredentialsException(“请重新登录”));
AuthUrl authUrl = authUrlMapper.findOne(Example.of(new AuthUrl().setUrl(url))).orElse(null);
if (authUrl == null) {
return true;
}
List<Long> uIds = authUrl.getUIds();
return uIds == null || uIds.isEmpty() || uIds.contains(profile.getId());
}
public void changePassword(String newPassword, Authentication authentication) {
Optional<UserProfile> optional = userProfileMapper.findOne(Example.of(new UserProfile().setEmail(authentication.getPrincipal().toString())));
UserProfile profile = optional.orElseThrow(() -> new BadCredentialsException(“请重新登录”));
String encode = passwordEncoder.encode(newPassword);
profile.setPassword(encode);
userProfileMapper.saveAndFlush(profile);
}
// **
}
Permission{
name//唯一,比如 PERM_GET_ALL_POSTS
urlPattern//比如:/posts/*
httpMethod// 比如:GET, 可用 enum 或直接用 Spring web HttpMethod. 常用的有 GET,POST,PUT,DELETE,PATCH
longDescription//其它辅助说明(用于页面补充)
}
那么 user 与 Permission 权限关系:
user->permission 1:n
2. Repository 类,PermissionRepository
3. Spring Security 中直接使用 Apply 。
allPermissions= permissionRepository.findAll(Sort.by(…))
http
.authorizeRequests(authorize ->
allPermissions.forEach(perm->{
authorize
.antMatchers(per.urlPattern, per.httpMethod).hasAuthority(perm.name)//这里查 Spring Security 文档,我记得以前不用 AntMatcher,而使用 RegexMatcher,表达比 ANT 方式更丰富。
})
4. 配置一个超级管理员,绕过所有权限(不读数据库),可以维护系统的 permission 列表。
默认给定一个管理员,配置所有权限。管理员可以用管理用户,可以管理用户权限(页面可以是 Checkbox,或者两列选择,等),最终影响 user -> permission 关系表。
所有新注册用户默认应该协商好,应该给那些权限,可以设计一些 DUMMY 权限比如 READ,那么在 persmission 表所有 httpmethod GET 权限就拿到了( UserDetailsService 中转换成实际 permissions 的 Authories )。
5. (扩展) 所有权限的初始数据可以用 Reflection 生成,在系统启动时初始化(添加,更新)。
6. (扩展) 可以添加 Role,role->Permission 可以是一对多的关系, 相当于权限分组了。在 UserDetailsService 的 findByusername 将所有的 Role 转换成 Permission 添加到 authories 中(因为上面的 Spring Security 中只配置比较 Permission )。这样的话,数据库关系变成 user->role>permission 1:n,1:n 。
7. (扩展) 所有前端的权限可以登录时拿到一个个人的允许的 permission 列表,可以用来辅助前端的页面控制。比如没有授权 PERM_GET_ALL_POSTS 的时候,可以从页面把顶级菜单上的 posts 去掉了。API 资源本身就是可以归类的,我从来没用过 V 站那些资源共享版本中贴的那些什么功能模块与权限配置表。
我遵循的一个原则,用户细粗度的行为(一个点击,一个操作)在一个应用程序中基本是可以固定下来的。所以 每一个不同操作最终变成一个不同的权限,Permission 在你的项目(应用)上线时候,基本可以是固定下来的,而 Role 完全可以由用户随便添加,随意修改。
这种灵活设计,对用户和开发人员都是作茧自缚,用处不大,技术没含量,很费事。基本过去十几年的项目经验可以肯定的说,基本上都是可以固定的 ROLE 搞定,结果大量的时间去开发所有权限系统。为什么用户会强调 ROLE 要灵活配置,说白了一点,从需求角度来分析,就是它自己需求不确定,不知道要做什么东西。
ABAC 更的多关注对一个资源的个别属性的访问控制权限,更细的控制。这个除非是基于传统数据模型的的开发,比如传统的 MIS 之类的系统。我觉得用在 API 的控制不大可能 。传统基于数据的开发,实现也不难。以前的 JBoss 下的 http://picketlink.org/ 应该相应的方案,记得见过了。数据模型,比如 JPA Entity,每个属性用某个 Annotation 标注,全部运行时可以提取出来 ,一样可以存放在数据库或者基于 LDAP 这种层层目录访问的方式 ,然后剩下就是就是在数据 CRUD 操作下控制了。
其实只要弄清楚,归类出来有几种人可以用这个系统(应用),角色就可以满足。欧美的项目我做很多,有电商,有支付,没有一个要这个种权限配置系统 。有些项目,人家一开始需求就很明确的提出了有几种人用这个系统,操作方式上有应该什么差别。