Spring-Security-文档笔记之认证组件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring-Security-文档笔记之认证组件相关的知识,希望对你有一定的参考价值。
参考技术A SecutiryContextHolder 用于存储已认证用户的信息, 它不关心用户是如何通过认证的, 只要包含一个值, 则这个值将被用来作为一个已认证用户. 这是一个jvm设置, 因此其所有方法都是静态的.通过配置指定相关策略. 其实现被委托给 SecurityContextHolderStrategy . 策略指定有两种方法, 一种是系统属性, 一种是调用静态方法.
其策略有三种:
获取用户信息:
类图:
存储Authentication对象.
在成功调用 AuthenticationManager.authenticate(Authentication) 方法后, 用于存储已认证用户的信息.
如果其 authenticated 属性值为false, Spring Security都将会对其进行验证.
Collection<? extends GrantedAuthority> getAuthorities() 用于获取授予认证主体的权限, 当没有权限时应返回空集合,而不是null.
Object getDetails() 方法用于存储认证请求信息, 如IP地址, 凭证序列号等.
Object getPrincipal() : 在使用用户名和密码登录验证的请求中, 在认证成功之前, 这通常是用户名, 认证成功后, 这通常是一个UserDetails对象.
boolean isAuthenticated() : 用于指示 AbstractSecurityInterceptor 是否将当前的Authentication对象传递给 AuthenticationManager 进行身份验证.
用于表示用户所获取的权限, 如角色. 如果使用用户名密码认证, 权限应由 UserDetailsService 加载.
它用字符串来表示, 以便能进行精确匹配.
用于处理认证请求. 认证后会将用户信息存储到SecurityContext中. 其最常用的实现为 ProviderManager .
必须对以下异常进行验证:
Authentication authenticate(Authentication authentication) throws AuthenticationException : 如果调用成功则返回一个完全填充(包含了较全面的用户信息)的Authentication对象.
最常用的 AuthenticationManager 实现. 它包含一个 AuthenticationProvider 集合. 每个provider对应一种身份验证方式, 因此通过 AuthenticationManager 可以支持多种身份验证方式. 如果请求没有相应的provider, 则将抛出 ProviderNotFoundException .
此外, ProviderManager还可以配置一个parent, 当ProviderManager无法进行认证时, 可以调用这个parent. 这样可以在有多个ProviderManager实例时, 通过parent来处理公共认证方式. parent可以是任何 AuthenticationManager 实例, 但通常为 ProviderManager .
ProviderManager还负责在认证成功后清除用户凭证(密码). 其 eraseCredentialsAfterAuthentication 属性值默认为true. 这对于通过缓存用户信息再进行认证的场景可能有影响(因为密码被清除了). 解决方式是设置 eraseCredentialsAfterAuthentication 为false.
认证事件
可通过 AuthenticationEventPublisher 来发布认证事件(成功,失败). 默认是一个Null实现(不发布事件). 因此如果需要发布事件,则需要注入对应的bean( DefaultAuthenticationEventPublisher ). ProviderManager的parent通常不需要配置publisher, 因为manager可以对parent的认证结果发布相应的事件, 从而造成事件 的重复发布.
AuthenticationManager类图:
定义认证方式.
在 ExceptionTranslationFilter 中用来定义认证方案. 即返回给客户端响应以要求客户端提供何种方式的认证.
类图:
身份验证的一个基础Filter.
类图:
Spring-Security:认证后调用方法
【中文标题】Spring-Security:认证后调用方法【英文标题】:Spring-Security: Call method after authentication 【发布时间】:2011-02-04 11:38:26 【问题描述】:我想跟踪用户何时登录我的应用程序。我有一些代码想在用户通过身份验证后立即执行。问题是,我不知道应该在哪里调用它。 spring-security 有办法在认证后调用方法吗?
【问题讨论】:
【参考方案1】:如果您想避免阅读所有主题:带有注释和更多解释性的精选版本:
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
@Component
public class LoginSuccessListener implements ApplicationListener<AuthenticationSuccessEvent
@Override
public void onApplicationEvent(AuthenticationSuccessEvent evt)
// if you just need the login
String login = evt.getAuthentication().getName();
System.out.println(login + " has just logged in");
// if you need to access full user (ie only roles are interesting -- the rest is already verified as login is successful)
User user = (User) evt.getAuthentication().getPrincipal();
System.out.println(user.getUsername() + " has just logged in");
【讨论】:
【参考方案2】:身份验证确实不一定意味着成功登录。用户可以通过例如双向 SSL(X.509 证书)成功验证,如果会话并发管理设置为 max-sessions="1"
并且这是第二次并发登录,Spring Security 仍会将您重定向到错误页面试图。如果您的设置很简单,没有会话并发控制,您可以假设 login = authentication 用于所有实际目的。否则,例如,如果您有记录数据库中每次成功 登录的逻辑,您将不得不在实际 登录时调用此逻辑,而不是在此时的认证。一种方法(绝不是最佳的,受限于我对 Spring Security 框架的有限理解)是实现您自己的ConcurrentSessionControlAuthenticationStrategy
(单击here 获取源代码)并将其注入您的Spring 中的CompositeSessionAuthenticationStrategy
安全(3.2 及以上)配置 XML:
<http>
.
.
<session-management session-authentication-strategy-ref="sas" />
.
.
</http>
.
.
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="path.to.my.implementation.of.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1"/>
<beans:property name="exceptionIfMaximumExceeded" value="true"/>
<beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy"/>
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
我宁愿将自定义 PostLogin
处理程序注入框架的 ConcurrentSessionControlAuthenticationStrategy
,而不是将其复制粘贴到我的自定义 ConcurrentSessionControlAuthenticationStrategy
并对其进行修改,但我不知道有什么方法可以现在做这个。
更完整的配置示例可以找到here。
【讨论】:
【参考方案3】:如果您想继续使用默认行为但只是在执行您自己的业务逻辑之间,您可以在返回之前extend SimpleUrlAuthenticationSuccessHandler
并调用super.onAuthenticationSuccess(request, response, authentication);
。更多详情请参考https://***.com/a/6770785/418439
【讨论】:
这是我通常做的事情,如果您不需要更改原始实现中的任何内容而只需要额外的功能,我建议您也这样做。我创建了一个 ChainAuthenticationSuccessHandler,然后它将调用我的自定义处理程序和现有的处理程序之一,如SimpleUrlAuthenticationSuccessHandler
。我发现它比扩展 Spring 的类更可靠、更干净。我想您也可以在原始处理程序之上创建某种装饰器类以避免继承,但链式解决方案对我更有吸引力。【参考方案4】:
可能对某人有用... 在 Spring 3 的情况下,配置安全性:
<security:http use-expressions="true" auto-config="true">
<security:intercept-url pattern="..."/>
<security:form-login
authentication-failure-handler-ref="authFailureHandler"
authentication-success-handler-ref="authSuccessHandler"/>
<security:logout success-handler-ref="logoutSuccessHandler"
invalidate-session="true"/>
<security:session-management session-fixation-protection="newSession"/>
</security:http>
<bean id="authFailureHandler" class="mine.AuthenticationFailureHandlerImpl"/>
<bean id="authSuccessHandler" class="mine.AuthenticationSuccessHandlerImpl"/>
<bean id="logoutSuccessHandler" class="mine.LogoutSuccessHandlerImpl"/>
并实现一个适当的类:
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
//do what you want with
response.getOutputStream().write("success".getBytes());
您可以通过该 xml 配置链接资源。
【讨论】:
好东西!感谢您的身份验证成功处理程序参考 如果我想添加一个小动作,然后继续正常处理,会怎样?【参考方案5】:最好的方法是创建一个应用程序监听器并将其注册到 spring 安全上下文中。
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
public class AuthenticationSuccessListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent>
@Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent event)
System.out.println("User Logged In");
确保将上面的类添加到 spring-security.xml 作为一个 bean。您可以侦听许多其他类型的安全事件侦听器,检查类型层次结构以获取您可以侦听的所有安全事件类型的列表。
【讨论】:
视情况而定,但这通常是我的选择。如果您需要创建身份验证事件的副作用,请使用 ApplicationListener。如果您需要指定应如何处理身份验证过程,请使用处理程序。在这种情况下,我会选择“跟踪身份验证操作”,因为它更像是一种副作用。【参考方案6】:ByteClip 上的这个链接Post Authentication Logic 解释了如何在成功认证后执行一些逻辑而不干扰 spring 安全过滤器链
【讨论】:
【参考方案7】:只需编写自己的 SpringSecurityFilter 并在调用身份验证提供程序后立即将其添加到过滤器链中。
package my.code;
public class AuditFilter extends SpringSecurityFilter
public void doFilterHttp(...) throws ...
application code to run before request is processed
chain.doFilter(...);
application code to run after request has fully processed
然后在您的配置 XML(无论您在哪里设置安全过滤器链)中添加如下一行:
<bean id="auditFilter" class="my.code.AuditFilter>
<security:custom-filter position="LAST"/> <-- you can change the position
</bean>
【讨论】:
请注意 SpringSecurityFilter 在 Spring Security 3 中更改为通用 Spring web GenericFilterBean。以上是关于Spring-Security-文档笔记之认证组件的主要内容,如果未能解决你的问题,请参考以下文章