繁体   English   中英

在 Spring 安全性中捕获 Remember-Me 身份验证事件

[英]Catching Remember-Me Authentication Events in Spring Security

我正在开发一个应用程序,我需要在其中捕获并响应身份验证事件以采取适当的措施。 目前,当用户手动登录时,我可以很好地捕捉到AuthenticationSuccessEvent Spring 抛出的问题。 我现在正在尝试实现 Remember-Me 功能。 日志记录帮助我弄清楚我想要捕获的事件是InteractiveAuthenticationSuccessEvent 有人可以看看下面的代码并帮助我响应这个新事件吗?

@Override
public void onApplicationEvent(ApplicationEvent event) {
    log.info(event.toString()); // debug only: keep track of all events
    if (event instanceof AuthenticationSuccessEvent) {
        AuthenticationSuccessEvent authEvent = (AuthenticationSuccessEvent)event;
        lock.writeLock().lock();
        try {
            sessionAuthMap.put(((WebAuthenticationDetails)authEvent.getAuthentication().getDetails()).getSessionId(), authEvent.getAuthentication());
        } finally {
            lock.writeLock().unlock();
        }
    } else if (event instanceof HttpSessionDestroyedEvent) {
        HttpSessionDestroyedEvent destroyEvent = (HttpSessionDestroyedEvent)event;
        lock.writeLock().lock();
        try {
            sessionAuthMap.remove(destroyEvent.getId());
        } finally {
            lock.writeLock().unlock();
        }
    }
}

附加信息:

我在原始帖子中没有提到在 Map 中存储 Session Id 和身份验证 object 的要求是因为我使用的是 Google 地球插件。 GE 充当一个单独的、不相关的用户代理,因此用户的 session 信息永远不会被 GE 传递给服务器。 出于这个原因,我重写了来自 GE 的请求 URL 以包含用户的活动 Session Id(来自上述地图)作为参数,因此我们可以验证所述 Z71C7AE294B7ABD866B3FB295B3B9 确实对登录用户有效。 所有这一切都已到位,因为我们拥有 GE 需要的 KML,但我们不能允许用户通过 Firebug 或您拥有的直接获取未受保护的 URL。

Spring 配置:(抱歉,格式有点捏造)

<sec:http use-expressions="true">
<sec:intercept-url pattern="/Login.html*" access="permitAll"/>
<sec:intercept-url pattern="/j_spring_security*" access="permitAll" method="POST"/>
<sec:intercept-url pattern="/main.css*" access="permitAll"/>
<sec:intercept-url pattern="/favicon.ico*" access="permitAll"/>
<sec:intercept-url pattern="/images/**" access="permitAll"/>
<sec:intercept-url pattern="/common/**" access="permitAll"/>
<sec:intercept-url pattern="/earth/**" access="permitAll"/>
<sec:intercept-url pattern="/earth/kml/**" access="permitAll"/>
<sec:intercept-url pattern="/earth/js/**" access="permitAll"/>
<sec:intercept-url pattern="/css/**" access="permitAll"/>   
<sec:intercept-url pattern="/resource*" access="permitAll"/>
<sec:intercept-url pattern="/geom*" access="hasRole('ROLE_SUPERUSER')"/>    
<sec:intercept-url pattern="/status/**" access="permitAll"/>    
<sec:intercept-url pattern="/index.html*" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/project.html*" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/js/**" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/help/**" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/app/**" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/data/**" access="hasRole('ROLE_USER')"/>   
<sec:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/> 
<sec:intercept-url pattern="/session/**" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/" access="hasRole('ROLE_USER')"/>
<sec:intercept-url pattern="/**" access="denyAll"/>
<sec:intercept-url pattern="**" access="denyAll"/>

<sec:session-management session-fixation-protection="none" />

<sec:form-login login-page="/Login.html${dev.gwt.codesrv.htmlparam}" default-target-url="/index.html${dev.gwt.codesrv.htmlparam}" authentication-failure-url="/Login.html${dev.gwt.codesrv.htmlparam}"/>
<sec:http-basic/>
<sec:logout invalidate-session="true" logout-success-url="/Login.html${dev.gwt.codesrv.htmlparam}"/>
 <sec:remember-me key="[REMOVED]" />
 </sec:http>

<bean id="authenticationEventPublisher" class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher" />

<bean id="org.springframework.security.authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <property name="authenticationEventPublisher" ref="authenticationEventPublisher"/>
    <property name="providers">
        <list>
            <ref bean="authenticationProvider" />
            <ref bean="anonymousProvider" />
        </list>
    </property>
</bean>

<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
    <property name="passwordEncoder" ref="passwordEncoder"/>
    <property name="saltSource" ref="saltSource"/>
    <property name="userDetailsService" ref="userService" />
</bean>

<bean id="anonymousProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
    <property name="key" value="[REMOVED]" />
</bean>

请阅读这篇文章底部的更新

您是否尝试过基于“InteractiveAuthenticationSuccessEvent 的事件实例”添加另一个“else if”?

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    log.info(event.toString()); // debug only: keep track of all events
    if (event instanceof AuthenticationSuccessEvent) {
        AuthenticationSuccessEvent authEvent = (AuthenticationSuccessEvent)event;
        lock.writeLock().lock();
        try {
            sessionAuthMap.put(((WebAuthenticationDetails)authEvent.getAuthentication().getDetails()).getSessionId(), authEvent.getAuthentication());
        } finally {
            lock.writeLock().unlock();
        }
    } else if (event instanceof InteractiveAuthenticationSuccessEvent) {
        InteractiveAuthenticationSuccessEvent authEvent = (InteractiveAuthenticationSuccessEvent)event;
        lock.writeLock().lock();
        try {
            sessionAuthMap.put(((WebAuthenticationDetails)authEvent.getAuthentication().getDetails()).getSessionId(), authEvent.getAuthentication());
        } finally {
            lock.writeLock().unlock();
        }
    } else if (event instanceof HttpSessionDestroyedEvent) {
        HttpSessionDestroyedEvent destroyEvent = (HttpSessionDestroyedEvent)event;
        lock.writeLock().lock();
        try {
            sessionAuthMap.remove(destroyEvent.getId());
        } finally {
            lock.writeLock().unlock();
        }
    }
}

更新:您的问题基本上是,“我怎样才能让一个 http 客户端(即 Google 地球插件)在我的网站上显示为使用另一个 http 客户端(用户的浏览器)登录的人?” 即使您可以让它发挥作用,从安全角度来看,这似乎也不是一个好主意。 另一个有趣的问题是,“除了让插件通过 http 请求 KML 文件之外,我如何将 KML 加载到 Google 地球插件中?” 根据他们的文档,有一个方法,parsekml(),它接受一个包含 KML 数据的字符串。 因此,理论上您可以使用来自用户浏览器的 JavaScript/AJAX 调用加载受保护的 KML 数据,这将与您网站的正常安全设置兼容,然后将返回的 KML 传递给 parsekml()。

根据spring 文档,“在 Spring 安全 3 中,用户首先由 AuthenticationManager 进行身份验证,一旦成功通过身份验证,就会创建 Z21D6F40CFB511982E44Z7E0E250A955”。

相反,您可以实现自己的AuthenticationSuccessHandler (可能通过子类SavedRequestAwareAuthenticationSuccessHandler )。 您可以在onAuthenticationSuccess方法中放置您想要的任何逻辑,因此将现有逻辑移到那里:

public class MyAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    // declare and initialize lock and sessionAuthMap at some point...
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, 
            HttpServletResponse response, Authentication authentication) 
            throws ServletException, IOException {
        lock.writeLock().lock();
        try {
            sessionAuthMap.put(request.getSession().getId(), authentication);
        } finally {
            lock.writeLock().unlock();
        }
        super.onAuthenticationSuccess(request, response, authentication);
    }
}

然后,更新您的配置,以便 Spring Security 在身份验证过程中调用此 class。 就是这样:

第 1 步:自定义由<form-login>元素创建的UsernamePasswordAuthenticationFilter 特别是,将其放入您的<http>元素中:

<sec:custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" />

第 2 步:定义 myFilter,并将MyAuthenticationSuccessHandler钩入其中。

<bean id="myFilter" 
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="authenticationFailureHandler" ref="myAuthenticationSuccessHandler" />
    <property name="authenticationSuccessHandler" ref="myAuthenticationFailureHandler" />
</bean>

<bean id="myAuthenticationSuccessHandler" 
    class="my.MyAuthenticationSuccessHandler">
<!-- set properties here -->
</bean>

<!-- you can subclass this or one of its parents, too -->
<bean id="myAuthenticationFailureHandler" 
    class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
    <!-- set properties such as exceptionMappings here -->
</bean>

有关详细信息,请参阅http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html 另请参阅AbstractAuthenticationProcessingFilter文档。

顺便说一句,您的问题让我想起了 OAuth。 本质上,由于资源所有者授权,您正在向客户端发出访问令牌。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM