2-1 Spring Security权限管理框架介绍
- 讲解Spring Security架构及核心组件。
包括:认证、权限拦截、数据库管理 、权限缓存、自定义角色。 - Spring Security环境的搭建与使用。
使用springboot来搭建一套环境。结合项目中的一些例子来做一些权限管理的case。 - Spring Security优缺点总结。
结合 2 中一些case的实现,来总结Spring Security的优缺点。
Spring Security提供了很多过滤器。它们拦截servlet请求,并将这些请求转交给 认证处理过滤器 和访问角色过滤器 进行处理。并强制安全性认证用户身份和用户权限 以达到保护web资源的目的。
Spring Security安全机制包括两个主要的操作,认证和验证。验证又可以称为权限控制。这是Spring Security的两个主要的方向。认证是为用户建立一个他所声明的主体的过程。这个主题一般是指用户、设备、或可以在你系统执行行动的其他系统。验证指一个用户能否在你的应用 中执行某个操作。在到达授权判断之前,身份的主体已经有身份验证过程建立了。
在身份验证层面,Spring Security只是各种身份验证模式。这些验证模型绝大多数由第三方体提供、或正在开发的由标准机构提供的。
接下来说几种常见的验证模式。
- Basic认证,是HTTP 1.0中引入的认证方案之一。虽然方案比较古老,同时存在安全缺陷,但由于实现简单,所以仍有部分场景下在使用,例如Tomcat自带的有个manager项目,访问这个项目需要Basic认证。
这种方式 针对特定的资源,需要提供用户名和密码认证后才可访问。其中密码是使用明文传输的。
一个请求到来时,弹出对话框。用户输入用户名和密码,并用 “用户名:密码" base64进行编码,浏览器会在http报文头部加入base64编码的内容。服务器解析出来这些信息并认证通过,才可继续访问。
使用http Basic 身份验证 有两个明显的缺点。1.他是无状态的。导致每次通信都要带上通信信息,即使是已经认证过的资源。2.传输安全性不足,认证信息用的base64编码,基本上就属于明文传输。很容易被截取报文,并盗取认证信息。 - Digest认证。主要是为了解决Basic认证的安全问题。用于替代原来的basic模式。当访问特定资源时,依然弹出对话框,让用户输入用户名和密码。浏览器会对用户名、密码、http请求方法、被请求资源的uri等组合后进行MD5运算,之后把计算得到的摘要信息发送给服务器,服务器web容器获取到报文http头部相关认证信息后,从中获取到userName,根据userName获取对应的密码。同样对用户名、密码、http请求方法、被请求资源的uri等组合后进行MD5运算。计算的结果进行比较。如果相同,认证通过。其实,通过hash算法对通信双方身份进行认证十分常见。他的好处就是不必把包含密码的信息对外传输,只需要将这些密码信息扎入对方给定的随机值然后来计算出hash值,最后将hash值传给对方,对方就可以认证你的身份。
Disest模式避免密码在网络上的明文传输,提高了安全性,但它仍然存在缺点。比如:认证的报文被攻击者拦截到,攻击者也可以获取到资源。 - X.509认证。X.509是一种非常通用的证书认证格式。所有的X.509证书,包含以下数据。 X.509的版本号、证书持有人的公钥、证书的序列号。
这里我们重点对序列号做一下说明。证书的序列号是CA给与的,每一个证书分配的,唯一的数字型编号。当证书被取消时,实际是这个序列号放入由CA签发的,证书的黑名单列表中。这也是序列号唯一的原因。除此之外,X.509证书还包含主题信息、证书的有效期、认证机构发布的数字签名、签名的算法等。X.509格式的证书,目前已经被微软、王景和其他许多公司广泛的应用于对电子邮件信息进行签名,对程序代码进行认证,以及对其他类型的数据进行认证等。 - LDAP是轻量目录访问协议。英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。企业内部需要认证的服务很多,员工需要记住很多的密码,即使对这些密码进行相同的密码设置,也是存在很大的安全隐患。许多企业都会遇到这种情况,每一个新员工带来的时候,管理员需要初始化很多密码,而这些密码都被设置成了类似6个8这种弱密码。由于各种软件的认证机制之间没有使用一个统一的标准,员工无法一次性修改所有密码。这导致即使是很多入职很久的员工都在使用这个众所周知的密码。另外一个问题是公司在增加内部服务的时候,管理员需要重新为所有员工初始化新的账户信息,对于一个有上千员工的企业来说这将是一个灾难。如果可以为各种软件提供一个标准的认证机制,所有的软件就可以不使用各自独有的管理方法,而是通过这种统一的方式进行认证,这样就解决了很多企业遇到的这个问题。统一身份认证主要是改变原有的身份认证策略。只需要软件都通过LDAP认证,用户的所有信息都存储在LDAP Server中。终端用户在需要使用公司内部服务的时候,都需要通过LDAP的服务器认证,每一个员工都只需要记住一个密码。在需要修改用户信息的时候,只需要使用管理员提供的web界面,直接修改你在LDAP中的信息 即可。目前大公司内部基本上都使用LDAP认证。
- 基于表单的认证。提供简单的用户接口来验证用户名密码,就不做过多的说明了。
Spring Security 还支持很多的身份验证模式,当然我们介绍的是属于最常见的。
实际中这些基本的认证还是不够的,有时你需要根据主体和应用交互的方式,来应用不同的安全措施。例如:有可能你为了保证密码不被窃听,或受到中间人的攻击,希望请求只能通过HTTPS到达。为了帮助你实现这些目标,Spring Security 还支持自动的信道安全,它整合了jcaptcha这个验证码插件。
2-2 Spring Security常用权限拦截器讲解
Spring Security提供了很多的过滤器,他们拦截servlet请求。并将这些请求转交给认证处理过滤器和访问角色过滤器进行处理。并强制安全性认证用户身份和权限,已达到保证web资源的目的。那他到底有那些filter呢?这些filter都是做什么的呢?我们一起看一下。
- SecurityContextPersistenceFilter
//todo 深入学习,补充笔记
//ThreadLocal - LogoutFilter
在用户发起注销请求时销毁用户的session,清空SecurityContextHolder,重定向到注//销成功页面。可以与RememberMe功能结合。在注销的同时清空用户的Cookie。
//todo 待深入学习 - AbstractAuthenticationProcessingFilter
处理form请求的过滤器,与form所有有关的操作都在此进行的。
默认是通过用户名和密码判断用户是否有效,如果登陆成功则跳转到成功页面,他可能是登陆之前受保护的页面,页可能是默认的成功页面。登陆失败则跳转到失败页面。 - DefeatLoginPageGeneratingFilter
用于生成一个默认的登陆页面,默认的访问地址为spring_security_login.。这个默认的页面虽然支持输入用户名和密码,也支持rememberme等功能。但是因为太难看了,只能在演示时候做个样子,不能直接在实际项目中使用。 - BasicAuthenticationFilter
主要用来进行basic验证的。功能与AbstractAuthenticationProcessingFilter很类似。只是验证的方式不同。 - SecurityContextAwareRequestFilter
该过滤器是用来包装客户的请求,目的是在原来请求的基础上为后续程序提供一些额外的数据。比如:getRemoteUser时候直接返回当前登陆的用户名之类的。 - RememberAuthenticationFilter
该过滤器实现的是remember me功能,当用户Cookie中存在rememberme标记时,他会根据标记实现自动登陆,并创建SpringContext,授予对应的权限,SpringSecurity中的Remember me是依赖Cookie实现的,当用户在登陆使用Remember me时,系统将会在用户登陆成功时,为用户生成一个唯一的标识。 并将这个标识保存在Cookie中 。我们可以通过浏览器查看用户电脑中的Cookie。 - AnonymousAuthenticationFilter
为了保证我们操作的统一性。当用户没有登陆时,默认为用户分配匿名用户的权限。当然了启动项目中会关掉匿名用户。 - ExceptionTranslationFilter
为了处理FilterSecurityInterceptor中抛出的异常。然后将请求重定向到对应的页面,返回对应的响应错误的代码,我们在项目开发中都要对项目的异常进行全局的处理。 - SessionManagermentFilter
主要是为了防御会话伪造攻击,这个主要是在用户登陆成功之后,销毁用户的当前session,并重新生成一个session。 - FilterSecurityInterceptor
用户的权限控制都包含在这个过滤器中。如果用户尚未登陆,则抛出用户尚未登陆异常;如果用户已经登陆,但是没有访问当前资源的权限,抛出拒绝访问的异常;如果用户已经登陆且具备访问当前资源的权限则放行。
FilterChainProxy
按照顺序来调用一组Filter,使得这些Filter既能完成验证授权的本职工作,又能响应Spring IOC的功能,来很方便的得到其他依赖的资源。
2-3 Spring Security数据库管理讲解
当一个用户登陆时,会先执行身份验证,如果身份验证未通过,则会要求用户重新认证。(相当于用户名或密码输入错误,需要用户冲i性能输入用户名或密码。)当用户身份验证通过后,则会调用角色管理器,看看他是否可以访问。这里如果要使用数据库管理用户及权限,则需要自定义用户登陆 功能。而Spring Security已经为我们提供好了接口。UserDetailService:
UserDetailService只有一个方法, loadUserByUsername(String username); 根据用户名获取用户信息。返回UserDetails对象。
UserDetails也是一个接口
getAuthorities()中存储了用户所有的权限。
还提供了用户是否过过期,用户是否被锁定‘,证书是否过期,用户是否有效这几个方法。这几个方法任何一个返回false,则用户的凭证视为无效。
这里需要特别注意一下Authentication和UserDetails对象的区分。Authentication对象才是Spring Security使用的,进行安全访问控制信息的安全对象。实际上Authentication对象有未认证和已认证的两种状态,在作为参数传入认证管理器的时候,他是一个未认证的对象。他从客户端获取用户的身份信息,如:用户名密码,可以是从一个登陆页面,也可以从Cookie中获取 并由系统自动构成一个Authentication对象。
而我们这里提到的UserDetails代表的是用户安全信息的源.这个源可以是从数据库,LDAP服务器,CA中心返回。Spring Security就是要把这个未认证的Authentication对象和UserDetails进行匹配,成功狗将UserDetails中的用户权限信息拷贝到Authentication中,组成一个完整的Authentication对象,与其他组件进行共享,UserDetails即可从数据库中返回,也可从其他的,如LDAP中返回。这取决于你的系统中用什么来存储用户信息和权限,以及相应的认证提供者。
回到Spring Security数据库管理的话题上。
当我们需要使用数据库管理用户时 ,我们需要手动实现UserDetailsService接口中的loadUserByUsername(String username)方法。
需要以下几张表:用户表,角色表,权限表,用户角色关系表,权限角色关系表,UserDetails中的用户状态通过用户表中的属性来填充。UserDetails中的权限集合则是通过权限表,用户角色关系表,权限角色关系表 构成的RBAC模型提供如此一来我们就可以把用户认证和用户权限集合都放在数据库中进行管理。