spring-security

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-security相关的知识,希望对你有一定的参考价值。

参考技术A

在使用spring-security时,我们应该去思考一些问题:

客户端发起请求到最终的servlet可能会经过如下过程:

我们可以思考一下,权限认证是不是也是其中某一个或者某几个filter呢?

DelegatingFilterProxy并不是SpringSecurity提供,而是Spring框架本身就存在的。它继承自GenericFilterBean,Servlet容器在启动的时候就会执行GenericFilterBean的init方法。

我们看看子类DelegatingFilterProxy的initFilterBean()方法里面做了什么事

在debug模式下我们可以看到真实的具体信息

通过上面源码的解析我们能够发现DelegatingFilterProxy这个过滤器在初始的时候从Spring容器中获取了 FilterChainProxy 这个过滤器链的代理对象,并且把这个对象保存在了DelegatingFilterProxy 的delegate属性中。那么当请求到来的时候会执行DelegatingFilterProxy的doFilter方法,那么我们就可以来看下这个方法里面又执行了什么

实际流程变为:

我们需要了解的概念,SpringSecurity中可以存在多个过滤器链,而每个过滤器链又可以包含多个过滤器

SpringSecurity中的主要过滤器

先前我们讲到,会构造出一个虚拟链路执行对应的filter。 VirtualFilterChain

decide方法在做投票选举,第一次的时候回抛出AccessDeniedException异常,而抛出的异常会
被ExceptionTranslationFilter中的catch语句块捕获,进而执行handleSpringSecurityException方法。

基于SpringBoot的自动装配,第三方框架要加载的信息在spring.factories中

这三个类中与DelegatingFilterProxy有关系的是SecurityFilterAutoConfiguration

我们来看一下这里面的构建逻辑是如何处理的

从ServletContextInitializer.onStartU()开始分析

至此,我们可以看到在springboot中,通过DelegatingFilterProxyRegistrationBean创建了一个,DelegatingFilterProxy过滤器并且执行了拦截地址是 /*。后续的流程就和xml流程一致,通过FilterChainProxy处理。

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的主要内容,如果未能解决你的问题,请参考以下文章