7

我正在开发一个应用程序,我需要在其中捕获并响应身份验证事件以采取适当的措施。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();
        }
    }
}

附加信息:

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

Spring Config:(对不起,格式有点捏造)

<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>
4

2 回答 2

4

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

您是否尝试过基于“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()。

于 2011-08-17T01:47:10.433 回答
2

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

相反,您可以实现自己的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 在身份验证过程中调用此类。就是这样:

第 1 步:自定义元素UsernamePasswordAuthenticationFilter创建的<form-login>元素。特别是,将其放入您的<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。本质上,由于资源所有者授权,您正在向客户端发出访问令牌。

于 2011-08-24T15:16:02.493 回答