spring-security(十一)Web应用认证过程

前言:
  本文将探讨当web应用中加入的spring security功能时,用户是如何认证的、安全上下文是如何创建的。
环境:
  spring boot 版本:1.5.4.RELEASE
1.一个典型的web应用的认证过程如下:
  • 用户访问网站主页,点击一个链接
  • 一个请求到达服务器,服务器发现用户正在访问一个受保护的资源
  • 因为到目前为止,用户还没有认证,所以服务器发回一个响应,指示用户必须先验证,这个响应或者是一个响应码,也可能是直接重定向到登录页
  • 根据认证的实现方式不同,用户可能会重定向到登录页等待用户输入用户名、密码等表单信息,或者浏览器以某种方式获取用户的证书(Basic认证中的弹出框,cookies机制,或者如X509认证方式中的证书)
  • 浏览器收集到认证信息后,会重新向服务器提交请求,这个请求也根据具体的实现方式而异,即可是一个带着表单信息的http post提交,也可以是http头部信息中包含认证信息详情的简单请求
  • 接着,服务器会验证用户提交的认证信息是否合法,如果合法就会执行下一步,如果不合法,通常情况下用户会被提示要重新认证(重新执行上面的两步)
  • 最初导致用户进行认证的请求将重新尝试执行。如果用户提供的认证信息有足够的权限访问受保护的资源,则之前的请求就会顺利完成,否则用户将收到一个代表权限不足的响应码:403

上面中大多数步骤在spring security中都有单独的类负责完成,按照使用的顺序主要有以下参与者
  • ExceptionTranslationFilter
  • AuthenticationEntryPoint
  • AuthenticationManager

2.ExceptionTranslationFilter
ExceptionTranslationFilter是一个过滤器,负责处理在spring security中抛出的所有异常。这些异常通常情况下都是由最主要的认证服务提供者AbstractSecurityInterceptor所抛出的。这个类我们后面会进一步探讨,现阶段我们只用知道他会产生认证异常就够了,不用去关心他是如何进行认证处理的。ExceptionTranslationFilter会根据产生的异常类型来确定是返回给客户端一个代表拒绝的403码(当用户已经认证过,但是访问了一个他没有权限访问的资源时,上面步骤中的第七步),或者是启动一个AuthenticationEntryPoint(当用户还没有认证时,上面步骤的第三步)
3.AuthenticationEntryPoint
AuthenticationEntryPoint负责上面步骤中的第三步。在有安全控制的web应用中都会有一个默认的认证策略,也都会提供自己的AuthenticationEntryPoint实现来让用户完成认证。
4. AuthenticationManager
一旦浏览器提供了认证的凭证信息(http post请求中的表单信息或者http头信息),服务器端就需要一种机制来收集这些信息,即执行上面步骤中的第六步,这个过程在spring security中叫做认证机制。如基于form的login和Basic认证机制中的http header,当凭证信息收集完成后,具体的认证机制将生成一个Authentication对象,并提供给AuthenticationManager。如果之后凭证信息有效,认证机制会从AuthenticationManager获取一个完全组装好的Authentication对象(包含权限信息),并把Authentication对象存储到SecurityContextHolder中,并重新执行触发认证的原始请求,如果凭证信息不合法,认证机制将要求用户重新认证。
5.另一个核心处理-如何在请求之间存储SecurityContext
在一个典型的web应用中,用户认证一次,他后续的操作将通过对应的session id来标示,不需要每次都认证,服务器负责在一次会话期间缓存这些认证信息。在spring security中这个功能是通过SecurityContextPersistenceFilter来实现的,默认情况下他会把认证信息存储到httpSession的一个属性中,在每一次http请求开始时,这个过滤器都会自动从session中拿出认证的上下文信息存储到SecurityContextHolder中,并且在请求结束后从SecurityContextHolder中把认证信息删除掉(为了安全考虑,确保能执行操作的用户的确是认证过的,并且不是其他人的认证信息)
在有一些web应用中(例如无状态的restful web服务)不使用session机制,因而每次请求都会进行认证,但是我们仍然需要把SecurityContextPersistenceFilter加到过滤器链中,主要就是确保每次请求完成后SecurityContextHolder都会被正确清空。

猜你喜欢

转载自fengyilin.iteye.com/blog/2411043