最新公告
  • 欢迎您光临站壳网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • SpringSecurity原理剖析与权限系统设计

    正文概述 webmaster   2019-12-5   572

    Spring Secutity和Apache Shiro是Java领域的两大主流开源安全框架,也是权限系统设计的主要技术选型。本文主要介绍Spring Secutity的实现原理,并基于Spring Secutity设计基于RBAC的权限系统。

    SpringSecurity原理剖析与权限系统设计

    一、技术选型

    1. 为何把Spring Secutity作为权限系统的技术选型,主要考虑了以下几个方面:
    2. 数据鉴权的能力:Spring Secutity支持数据鉴权,即细粒度权限控制。
    3. Spring生态基础:Spring Secutity可以和Spring生态无缝集成。

    多样认证能力:Spring Secutity支持多样认证方式,如预认证方式可以与第三方认证系统集成。

    SpringSecurity原理剖析与权限系统设计

    二、核心架构

    权限系统一般包含两大核心模块:认证(Authentication)和鉴权(Authorization)。

    • 认证:认证模块负责验证用户身份的合法性,生成认证令牌,并保存到服务端会话中(如TLS)。
    • 鉴权:鉴权模块负责从服务端会话内获取用户身份信息,与访问的资源进行权限比对。

    官方给出的Spring Security的核心架构图如下:

    SpringSecurity原理剖析与权限系统设计

    核心架构解读:

    • AuthenticationManager:负责认证管理,解析用户登录信息(封装在Authentication),读取用户、角色、权限信息进行认证,认证结果被回填到Authentication,保存在SecurityContext。
    • AccessDecisionManager:负责鉴权投票表决,汇总投票器的结果,实现一票通过(默认)、多票通过、一票否决策略。
    • SecurityInterceptor:负责权限拦截,包括Web URL拦截和方法调用拦截。通过ConfigAttributes获取资源的描述信息,借助于AccessDecisionManager进行鉴权拦截。
    • SecurityContext:安全上下文,保存认证结果。提供了全局上下文、线程继承上下文、线程独立上下文(默认)三种策略。
    • Authentication:认证信息,保存用户的身份标示、权限列表、证书、认证通过标记等信息。
    • SecuredResource:被安全管控的资源,如Web URL、用户、角色、自定义领域对象等。
    • ConfigAttributes:资源属性配置,描述安全管控资源的信息,为SecurityInterceptor提供拦截逻辑的输入。

    三、设计原理

    通过对源码的分析,我把Spring Security的核心领域模型设计整理如下:

    SpringSecurity原理剖析与权限系统设计

    全局抽象模型解读:

    • 配置:AuthenticationConfiguration负责认证系统的全局配置,GlobalMethodSecurityConfiguration负责方法调用拦截的全局配置。
    • 构建:AuthenticationConfiguration通过AuthenticationManagerBuilder构建认证管理器AuthenticationManager,GlobalMethodSecurityConfiguration会自动初始化AbstractSecurityInterceptor进行方法调用拦截。
    • Web拦截:HttpSecurity对Web进行安全配置,内置了大量GenericFilterBean过滤器对URL进行拦截。负责认证的过滤器会通过AuthenticationManager进行认证,并将认证结果保存到SecurityContext。
    • 方法拦截:Spring通过AOP技术(cglib/aspectj)对标记为@PreAuthorize、@PreFilter、@PostAuthorize、@PostFilter等注解的方法进行拦截,通过AbstractSecurityInterceptor调用AuthenticationManager进行身份认证(如果必要的话)。
    • 认证:认证管理器AuthenticationManager内置了多种认证器AuthenticationProvider,只要其中一个认证通过,认证便成功。不同的AuthenticationProvider获取各自需要的信息(HTTP请求、数据库查询、远程服务等)进行认证,认证结果全部封装在Authentication。需要加载用户、角色、权限信息的认证器(如密码认证、预认证等)需要对接UserDetailsManager接口实现用户CRUD功能。
    • 鉴权:权限拦截器AbstractSecurityInterceptor通过读取不同的SecurityMetadataSource加载需要被鉴权资源的描述信息ConfigAttribute,然后把认证信息Authentication、资源描述ConfigAttribute、资源对象本身传递给AccessDecisionManager进行表决。AccessDecisionManager内置了多个投票器AccessDecisionVoter,投票器会将鉴权信息中的ConfigAttribute转换为SpringEL的格式,通过表达式处理器SecurityExpressionHandler执行基于表达式的鉴权逻辑,鉴权逻辑会通过反射的方式转发到SecurityExpressionRoot的各个操作上去。
    • 定制:通过WebSecurityConfigureAdapter可以定制HTTP安全配置HttpSecurity和认证管理器生成器AuthenticationManagerBuilder;通过AbstractPreAuthenticatedProcessingFilter可以定制预认证过滤器;通过UserDetailsManager和UserDetails接口可以对接自定义数据源;通过GrantedAuthority定制权限信息;通过PermissionEvaluator可以定制自定义领域模型的访问控制逻辑。

    四、应用集成

    理清Spring Security的定制点后,就可以在系统内部集成Spring Security了。

    这里使用预认证的方式,以适配第三方认证系统。AbstractPreAuthenticatedProcessingFilter提供了预认证的扩展点,基于该抽象类实现一个自定义认证过滤器。

    1. public class MyPreAuthFilter extends AbstractPreAuthenticatedProcessingFilter { 
    2.  @Override 
    3.  protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) { 
    4.  // 从第三方系统获取用户ID 
    5.  return userId; 
    6.  } 
    7.  @Override 
    8.  protected Object getPreAuthenticatedCredentials(HttpServletRequest request) { 
    9.  return ""
    10.  } 

    Spring Security会根据预认证过滤器getPreAuthenticatedPrincipal返回的用户ID信息,加载用户角色等初始信息。这里需要实现UserDetailsManager接口,提供用户信息管理器。

    1. @Service 
    2. public class MyUserManager implements UserDetailsManager { 
    3.  @Override 
    4.  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
    5.  // 从数据库加载用户信息 
    6.  return user
    7.  } 
    8.   
    9.  // 其他管理接口 

    UserDetails内包含了GrantedAuthority接口类型的权限信息抽象,一般可以基于它自定义角色和权限。Spring Security使用一种接口形式表达角色和权限,角色和权限的差别是角色的ID是以"ROLE_"为前缀。

    1. public class MyRole implements GrantedAuthority { 
    2.  private final String role; 
    3.  @Override 
    4.  public String getAuthority() { 
    5.  return "ROLE_" + role; 
    6.  } 
    7. public class MyAuthority implements GrantedAuthority { 
    8.  private final String authority; 
    9.  @Override 
    10.  public String getAuthority() { 
    11.  return authority; 
    12.  } 

    接下来注册自定义认证过滤器和用户管理器,这里需要实现WebSecurityConfigurerAdapter进行Web安全配置。

    1. @EnableWebSecurity 
    2. @EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.PROXY) 
    3. public class MySecurityConfig extends WebSecurityConfigurerAdapter { 
    4.  @Autowired 
    5.  UserDetailsManager userDetailsManager; 
    6.  @Bean 
    7.  protected AuthenticationProvider createPreAuthProvider() { 
    8.  // 注册用户管理器 
    9.  PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider(); 
    10.  provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper<>(userDetailsManager)); 
    11.  return provider; 
    12.  } 
    13.  @Override 
    14.  protected void configure(HttpSecurity http) throws Exception { 
    15.  // 注册预认证过滤器 
    16.  http.addFilter(new MyPreAuthFilter(authenticationManager())); 
    17.  } 

    这样,最简单的Spring Security框架集成内系统内部已经完成了。在系统的任意服务接口上可以使用如下方式进行鉴权。

    1. public interface MyService { 
    2.  @PreAuthorize("hasAuthority('QUERY')"
    3.  Object getById(String id); 
    4.   
    5.  @PreAuthorize("hasRole('ADMIN')"
    6.  void deleteById(String id); 

    PreAuthorize注解表示调用前鉴权,Spring使用默认使用动态代理技术生成鉴权逻辑。注解内配置了SpringEL表达式来定制鉴权方式。上述代码中,hasAuthority会检查用户是否有QUERY权限,hasRole会检查用户是否有ADMIN角色。

    使用动态代理的方式进行AOP,只允许在接口层面进行权限拦截,如果想在任意的方法上进行权限拦截,那么就需要借助于AspectJ的方式进行AOP。首先将注解EnableGlobalMethodSecurity的mode设置为AdviceMode.ASPECTJ,然后添加JVM启动参数,这样就可以在任意方法上使用Spring Security的注解了。

    1. javaagent:/path/to/org/aspectj/aspectjweaver/1.9.4/aspectjweaver-1.9.4.jar 

    以上还是只是以用户的身份信息(角色/权限)进行权限,灵活度有限,也发挥不了Spring Security的数据鉴权的能力。要使用数据鉴权,需要实现一个Spring Bean。

    1. @Component 
    2. public class MyPermissionEvaluator implements PermissionEvaluator { 
    3.  @Override 
    4.  public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) { 
    5.  // 自定义数据鉴权 
    6.  return false
    7.  } 
    8.  @Override 
    9.  public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { 
    10.  // 自定义数据鉴权 
    11.  return false
    12.  } 

    PermissionEvaluator会被自动注册到Spring Security框架,并允许在注解内使用如下方式进行鉴权。

    1. @PreAuthorize("hasPermission(#id, 'QUERY')"
    2. Object func1(String id) { 
    3. @PreAuthorize("hasPermission(#id, 'TABLE', 'QUERY')"
    4. Object func2(String id) { 

    其中,func1的注解表示校验用户是否对id有QUERY权限,代码逻辑路由到MyPermissionEvaluator的第一个接口。func2的注解表示校验用户是否对TABLE类型的id有QUERY权限,代码逻辑路由到MyPermissionEvaluator的第二个接口。PermissionEvaluator提供了权限系统中数据鉴权的扩展点,稍后会描述如何利用该扩展点定制基于RBAC的权限系统。

    五、权限系统

    构建基于RBAC(Role Based Access Control)的权限系统,需要明确用户、角色、权限、资源这几个核心的概念类的含义和它们之间的关系。

    资源:权限系统内需要安全控制的客体,一般是系统内的数据或功能。

    权限:描述了资源上的操作抽象,一般是一种动作。

    授权:是权限和资源的组合,表示对资源的某一个操作。

    角色:描述了一组授权的集合,表示一类特殊概念的功能集。

    用户:权限系统的主体,一般是当前系统的访问用户用户可以拥有多种角色。

    以下是我们设计的基于RABC的权限核心领域模型:

    SpringSecurity原理剖析与权限系统设计

    一般情况下,系统内需要权限管控的资源是无法用户自定义的,因为资源会耦合大量的业务逻辑,所以我们提供了自 资源工厂,通过配置化的方式构建业务模块所需的资源。而用户、角色、权限,以及授权记录都是可以通过相应的管理器进行查询更新。

    另外,资源抽象允许表达资源的继承和组合关系,继而表达更复杂的资源模型,资源统一鉴权的流程为:

    SpringSecurity原理剖析与权限系统设计

    • 执行鉴权时,首先看资源是原子资源还是组合资源
    • 对于原子资源,先查询是否有授权记录,再查看角色预授权是否包含当前授权,存在一种便成功。
    • 没有授权记录和角色预授权的原子资源,尝试用父资源(如果有的话)代替鉴权,否则鉴权失败。
    • 对于组合资源,先进行资源展开,获取子资源列表。
    • 遍历子资源列表,并依次对子资源进行鉴权,子资源鉴权结果汇总后,即组合资源鉴权结果。
    • 综上,基于统一资源抽象和资源配置化构建,可以实现资源的统一构建,继而实现统一鉴权。

    六、总结回顾

    本文从Spring Security的架构和原理出发,描述了开源安全框架对于认证和鉴权模块的设计思路和细节。并提供了系统内集成Spring Security的方法,结合RBAC通用权限系统模型,讨论了统一资源构建和统一鉴权的设计和实现。如果你也需要设计一个新的权限系统,希望本文对你有所帮助。

    1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
    2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
    3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
    4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
    5. 如有链接无法下载、失效或广告,请联系管理员处理!
    6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
    7. 如遇到加密压缩包,默认解压密码为"www.yoozai.net",如遇到无法解压的请联系管理员!
    悠哉网 » SpringSecurity原理剖析与权限系统设计

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    悠哉网 WWW.YOOZAI.NET
    悠哉网,用户消费首选的网站,喜欢你就悠哉一下。

    发表评论

    售后服务:

    • 售后服务范围 1、商业模板使用范围内问题免费咨询
      2、源码安装、模板安装(一般 ¥50-300)服务答疑仅限SVIP用户
      3、单价超过200元的模板免费一次安装,需提供服务器信息。
      付费增值服务 1、提供dedecms模板、WordPress主题、discuz模板优化等服务请详询在线客服
      2、承接 WordPress、DedeCMS、Discuz 等系统建站、仿站、开发、定制等服务
      3、服务器环境配置(一般 ¥50-300)
      4、网站中毒处理(需额外付费,500元/次/质保三个月)
      售后服务时间 周一至周日(法定节假日除外) 9:00-23:00
      免责声明 本站所提供的模板(主题/插件)等资源仅供学习交流,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担,有部分资源为网上收集或仿制而来,若模板侵犯了您的合法权益,请来信通知我们(Email: 80027422@qq.com),我们会及时删除,给您带来的不便,我们深表歉意!

    Hi, 如果你对这款模板有疑问,可以跟我联系哦!

    联系作者

    发表评论

    售后服务:

    • 售后服务范围 1、商业模板使用范围内问题免费咨询
      2、源码安装、模板安装(一般 ¥50-300)服务答疑仅限SVIP用户
      3、单价超过200元的模板免费一次安装,需提供服务器信息。
      付费增值服务 1、提供dedecms模板、WordPress主题、discuz模板优化等服务请详询在线客服
      2、承接 WordPress、DedeCMS、Discuz 等系统建站、仿站、开发、定制等服务
      3、服务器环境配置(一般 ¥50-300)
      4、网站中毒处理(需额外付费,500元/次/质保三个月)
      售后服务时间 周一至周日(法定节假日除外) 9:00-23:00
      免责声明 本站所提供的模板(主题/插件)等资源仅供学习交流,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担,有部分资源为网上收集或仿制而来,若模板侵犯了您的合法权益,请来信通知我们(Email: 80027422@qq.com),我们会及时删除,给您带来的不便,我们深表歉意!

    Hi, 如果你对这款模板有疑问,可以跟我联系哦!

    联系作者
    • 582会员总数(位)
    • 4743资源总数(个)
    • 142本周发布(个)
    • 11 今日发布(个)
    • 177稳定运行(天)

    提供最优质的资源集合

    立即查看 了解详情