RBAC(Role - Based Access Control)
用户 - 角色 -权限 ,都适用
理想中的权限管理
- 能实现角色级权限:RBAC
- 能实现功能级、数据级权限
- 简单、易操作、能够应对各种需求
Spring Security
- springSecurity介绍
- Spring Security 是基于 Spring 的身份认证(Authentication)和用户授权(Authorization)框架,提供了一套 Web 应用安全性的完整解决方案。其中核心技术使用了 Servlet 过滤器、IOC 和 AOP 等。
- 什么是身份认证? 身份认证指的是用户去访问系统资源时,系统要求验证用户的身份信息,用户身份合法才访问对应资源。常见的身份认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。
- 什么是用户授权?当身份认证通过后,去访问系统的资源,系统会判断用户是否拥有访问该资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问,这个过程叫用户授权。比如 会员管理模块有增删改查功能,有的用户只能进行查询,而有的用户可以进行修改、删除。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。
有很多过滤器,进行拦截servlter请求,并将请求进行认证和验证。
认证是为用户建立他所声明的主题过程。
验证是用户是否能够在软件中进行操作。
几种常见的验证方式:
- Basic 使用http1.0 账号密码进行验证,密码使用明文传输 账号:密码 + base64编码, 安全性不足
- Digest 用户名+密码+http请求方法+资源uri组合 进行md5 避免了密码的明文传输,安全性不足,会被拦截
- X.509 证书认证 版本号 公钥 序列号(CA唯一证书)
- LDAP 认证
- Form 表单认证
权限拦截
Spring Security中会有很多过滤器,将用户的请求 进行拦截,交给认证处理过滤器 以及 访问决策过滤器,进行用户身份、权限验证,
来看看涉及到的主要几个过滤器:
拦截器:
一、SecurityContextPersistenceFilter:
是第一个执行的过滤器,有两个用途:
1.判断用的sission是否已经存在在SecurityContext,如果存在就取出来放到Security上下文中的SecurityContextHolder中,供其他部分使用,不存在就创建一个在存入SecurityContextHolder中
2.在所有过滤器执行完毕之后,清空SecurityContextHolder,因为SecurityContextHolder是基于ThreadLocal的,如果最后没有清空ThreadLocal会受到服务器机制的影响
这里我们看下ThreadLocal
Threadlocal里面存放的东西是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,能够优雅的解决一些实际中的并发问题。
Threadlocal内部有一个ThreadMap
当使用Threadlocal存值时,会先获得当前线程对象,然后获得当前线程本地的对象,最后将当前使用的Threadlocal和要存入的对象,放进ThreadMap中,也就是说ThreadMap存储的是Threadlocal对象,这样的好处是,每个线程都对应一个本地变量的map。
Threadlocal的get()方法,如果Threadlocal没设置过值,那么调用get方法会间接调用初始值的一个方法,返回空
Threadlocal是解决线程安全问题的一个很好的思路,它通过为每一个线程提供一个独立的变量副本,解决并发访问的冲突问题,增加了并发性。
注意:当线程结束时要把当前Threadlocal里的信息移除掉,Threadlocal本身提供了一个remove方法,我们只要调用这个方法就可以了,从而清掉当前进程携带的信息。
二、LogoutFilter:
只处理注销请求,在发生注销请求时,销毁注销用户的sission,清空SecurityContextHolder,然后重定向到注销成功页面, 可以和关闭功能结合,在关闭时清空用户的cooike
三、AbstractAuthenticationProcessingFilter:
处理form登录的过滤器,与form登录有关的所有操作都是在这里进行的,登陆时判断用户名密码是否有效,有效的话就跳转到成功页面
四、DefaultLoginPageGeneratingFilter:
用于生成一个默认的登录页面,虽然有一些功能,但是太难看了,不能在实际项目中使用
五、BasicAuthenticationFilter:
用于Basic验证,与AbstractAuthenticationProcessingFilter类似但是验证方式不同
六、SecurityAuthenticationFilter:
用来包装客户的请求,目的实在原来请求的基础上对后续程序提供额外的数据,比如在remove user时直接提供当前登录的用户名之类的
七、RememberMeAuthenticationFilter:
实现RememberMe功能,当用户cookie中存在RememberMe标记时,会根据标记实现自动创建SecurityContext,授予相应权限 ,spring Security 中的RememberMe依赖cookie实现,当用户登录时选择使用RememberMe,就再用户登录后为用户生成一个唯一的标识,并将标识保存在cookie中
八、AnonymousAuthenticationFilter:
用于保证用户没有登录时,为用户分配匿名用户的权限,当然了,许多项目也会关闭掉匿名用户
九、ExceptionTeanslationFilter:
为了处理filterSecurityException抛出的异常,请求重定向到对应页面,或者返回对应的响应错误代码
十、SessionManagementFilter:
只要是为了防御会话伪造攻击,只要登录成功后销毁当前用户的当前sission,并从新生成一个sission就可以了
十一、FilterSecurityInterceptor:
用户的权限控制都包含在这个过滤器中,功能是:
1.如果用户尚未登陆就抛出尚未登录的异常
2.如果用户已经登录但是没有访问当前资源的权限,那么会抛出拒绝访问的异常
3.用户已登录也具有访问当前资源的权限就放行
这十一个拦截器是如何按照顺序执行的呢?
FilterChainProxy:这个类会按照顺序调用一组filter既能使用各自相应的工作,又能实现springioc得到其他依赖的资源
spring security 数据库管理
UserDetailsService
UserDetails
-
getAuthorities() 权限集合
-
getPassword() 密码
-
getUsername() 用户名
-
isAccountNonExpired() 账户没有过期
-
isAccountNonLocked() 账户没有被锁定
-
isCredentialsNonExpired() 证书没有过期
-
isEnabled() 账户是否有效
Authentication 是springsecurity进行安全访问控制的对象
-
getAuthorities() 权限集合
-
getCredentials() 获取凭证
-
getDetails() 获取认证一些额外信息
-
getPrincipal() 过去认证的实体
-
isAuthenticated() 是否认证通过
权限缓存
可以缓存UserDetailsService
CachingUserDetailsService
Ehcache
项目中我们会引入更多的cache 例如 Redis 不仅缓存用户,并且缓存用户权限
自定义决策
看上图
AbstractAccessDecisionManager 核心方法supports()
投票器概念 AccessDecisionVoter 有无权限访问的最终决定权
RoleVoter 最常见的投票器 中 vote 方法 会循环判断是否具有当前的权限
目前security 有三个投票器
- AffirmativeBased 一票通过方案
- ConsensusBased 一半以上投票通过才可以访问权限
- UnanimousBased 全部通过才可以访问
我们自定义决策直接继承AbstractAccessDecisionManager 就可以,不一定需要投票器
- Shiro 与 Spring Security对比
- Shiro 特点
- Shiro 是 Apache 下的项目,相对简单、轻巧,更容易上手使用。
- Shiro 权限功能基本都能满足,单点登录都可以实现。且不用与任何的框架或者容器绑定, 可以独立运行。
- Spring Security 特点
- Spring Security 相对 Shiro 上手更复杂;
- 2. Spring Security 功能比 Shiro 更加丰富些;
- 3. Spring Security 是 Spring 家族的产品,与 Spring 无缝对接, 社区资源相对比 Shiro 更加丰富;
- 4. Spring Security 对 Oauth2 也有支持, Shiro 则需要自己手动实现。而且 Spring Security 的权限细粒度更高
- 如何选择
- 如果项目中不是很庞大,没有用到 Spring,那就不要考虑使用 Spring Security ,Shiro 足够满足, 建议使用。
- 如果项目使用 Spring 作为基础,配合 Spring Security 做权限更加方便,而 Shiro 需要和 Spring 进行整合开发。
- Shiro 特点
我们会做个case来了解
GitHub :https://github.com/Andy-leoo/Rbac-learn.git