/Login
?答案 0 :(得分:9)
所有重要的魔法都在security filter chain。
某些组件会在某些时候检查请求是否经过身份验证。通常它是最后一个过滤器 - FilterSecurityInterceptor
(根据请求路径检查访问条件),但它可以是MethodSecurityInterceptor
(@Secured
注释检查),甚至是您自己的自定义代码。重要的是,此检查将以AuthenticationException
或AccessDeniedException
被抛出结束。
下一个重要组成部分是ExceptionTranslationFilter
。此过滤器检查抛出的异常是AuthenticationException
还是AccessDeniedException
并调用已配置的AuthenticationEntryPoint
。根据配置的身份验证机制,这可能会使用WWW-Authenticate
标头(例如BASIC auth)将重定向发送到登录页面或401响应。
所以基于FORM的登录的整个过程看起来像这样(它可能看起来像一团糟,但它实际上设计得很好,一旦你理解了这些原则就不那么复杂了):
/foo.html
发出请求
FilterSecurityInterceptor
针对您的安全表达式isAuthenticated()
进行检查并抛出AccessDeniedException
ExceptionTranslationFilter
抓取,后者又调用LoginUrlAuthenticationEntryPoint
301
/login.html
重定向回复
/login.html
发出另一个请求
FilterSecurityInterceptor
检查,对于此路径,允许匿名访问POST /login.html
UsernamePasswordAuthenticationFilter
AuthenticationManager
执行实际身份验证(将实际身份验证委托给其他组件 - 通常为DaoAuthenticationProvider
和UserDetailsService
)Authentication
令牌被标记为authenticated
并置于SecurityContextHolder
(因此可供其他组件使用)AuthenticationSuccessHandler
,这可能只是将用户重定向回/foo.html
SecurityContextPersistenceFilter
(检查SecurityContextHolder
)获取,该身份验证在HTTP会话上存储身份验证/foo.html
发出了另一个请求
SecurityContextPersistenceFilter
将会话中的身份验证还原到SecurityContextHolder
FilterSecurityInterceptor
再次检查您的访问规则,并允许进一步处理新近验证的请求(即调用调度程序servlet)/foo.html