Spring MVC 页面中来自嵌入式 Flex 应用程序的远程调用时出现 Spring 安全错误



我希望有人能帮我解决这个问题。我有一个Spring MVC应用程序(Spring 3)在Spring Security 3上运行良好,我们现在正在添加对Flex的支持,并将BlazeDS添加到应用程序和Spring Integration(1.5.0 M2)中,所有这些都开始工作正常,直到我们想通过Spring Security集成身份验证。Flex应用程序是一个"迷你"UI,充当两个用户之间的P2P聊天(通过消息传递),它嵌入在Spring MVC应用程序的JSP页面中,我们要做的是确保(从Flex应用程序)用户在显示聊天UI之前已登录。身份验证是从Spring MVC应用程序(Web表单)完成的,并且工作正常,但是每次我们访问包含Flex应用程序的Spring MVC页面并从Flex进行远程调用以获取当前用户详细信息时,我们都会得到一个异常:

flex.messaging.security.SecurityException: An Authentication object was not found in the SecurityContext

我们假设远程处理请求(从经过身份验证的会话发出)将以某种方式被拾取和识别,并且 Flex 客户端不需要再次进行身份验证。这里可能出了什么问题?这是我的 spring 安全配置和我的 flex 配置文件以及 web.xml:

安全性.xml:

<bean id="springSecurityFilterChain"
        class="org.springframework.security.web.FilterChainProxy">
        <sec:filter-chain-map path-type="ant">          
            <sec:filter-chain filters="none" pattern="/styles/**" />
            <sec:filter-chain filters="none" pattern="/js/**" />
            <sec:filter-chain filters="none" pattern="/images/**" />
            <sec:filter-chain 
                filters="securityContextPersistenceFilter,
                    logoutFilter,
                    usernamePasswordAuthenticationFilter,
                    anonymousAuthenticationFilter,
                    exceptionTranslationFilter,
                    menuLoaderRequestFilter,
                    filterSecurityInterceptor" 
                pattern="/web/**" />
            <sec:filter-chain 
                filters="securityContextPersistenceFilter,
                    usernamePasswordAuthenticationFilter,
                    exceptionTranslationFilter" 
                pattern="/do_login" />              
            <sec:filter-chain 
                filters="securityContextPersistenceFilter,
                    logoutFilter,
                    exceptionTranslationFilter" 
                pattern="/do_logout" />
        </sec:filter-chain-map>
    </bean>
    <bean id="securityContextPersistenceFilter"
            class="org.springframework.security.web.context.SecurityContextPersistenceFilter" />
    <bean id="usernamePasswordAuthenticationFilter"
        class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
        <property name="authenticationManager"
                ref="authenticationManager" />
        <property name="filterProcessesUrl" value="/do_login"/>
        <property name="authenticationFailureHandler">
            <ref bean="loginFailureHandler" />
        </property>
        <property name="authenticationSuccessHandler">
            <ref bean="loginSuccessHandler" />
        </property>
        <property name="usernameParameter" value="login_user" />
        <property name="passwordParameter" value="login_password" />
    </bean>
    <bean id="loginFailureHandler"
            class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
        <property name="defaultFailureUrl" value="/web/login?error=login.failure"/>
        <property name="exceptionMappings">
            <map>
                <entry>
                    <key>
                        <value>org.springframework.security.authentication.AuthenticationServiceException</value>
                    </key>
                    <value>/web/login?error=login.database.failure</value>
                </entry>
            </map>
        </property>
    </bean>
    <bean id="loginSuccessHandler"
            class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
        <property name="defaultTargetUrl" value="/web/index"/>
    </bean>
    <bean id="anonymousAuthenticationFilter"
        class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
        <property name="userAttribute"
                value="anonymousUser,ROLE_ANONYMOUS" />
        <property name="key" value="AD17JFJ005P00Z7MK" />
    </bean>
    <bean id="logoutFilter" 
        class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <!-- the post-logout destination -->
        <constructor-arg value="/web/login?success=login.loggedout"/>
        <constructor-arg>
            <array>
                <ref bean="logoutHandler" />
            </array>
        </constructor-arg>
        <property name="filterProcessesUrl" value="/do_logout"/>
    </bean>
    <bean id="logoutHandler" 
            class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
    <bean id="exceptionTranslationFilter"
            class="org.springframework.security.web.access.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint"
            ref="mainEntryPoint"/>
        <property name="accessDeniedHandler" ref="accessDeniedHandler"/>
    </bean>

    <bean id="mainEntryPoint" 
            class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">         
        <constructor-arg>
            <map>
                <entry>
                    <key>
                        <value>hasHeader('X-Requested-With', 'XMLHttpRequest')</value>                      
                    </key>
                    <ref bean="ajaxEntryPoint"/>
                </entry>
                <entry>
                    <key>
                        <value>hasHeader('Content-type', 'application/x-amf')</value>
                    </key>
                    <ref bean="flexEntryPoint" />
                </entry>
            </map>
        </constructor-arg>          
        <property name="defaultEntryPoint" ref="defaultEntryPoint" />
    </bean>
    <bean id="entryPointTemplate" abstract="true">
        <property name="loginFormUrl" value="/web/login"/>
    </bean>
    <bean id="ajaxEntryPoint" parent="entryPointTemplate"
            class="com.saes.support.security.AjaxAuthenticationEntryPoint" >
    </bean>
    <bean id="defaultEntryPoint" parent="entryPointTemplate"
            class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">       
    </bean>
    <bean id="flexEntryPoint" class="org.springframework.flex.security3.FlexAuthenticationEntryPoint">
    </bean>
    <bean id="accessDeniedHandler"
            class="com.saes.support.security.SAESAccessDeniedHandler">
        <property name="errorPage" 
                value="/web/errors/accessDenied"/>
    </bean>
    <bean id="filterSecurityInterceptor"
        class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
        <property name="authenticationManager"
                ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="decisionManager"/>
        <property name="securityMetadataSource">
            <sec:filter-security-metadata-source>
                <sec:intercept-url pattern="/web/profile/**" 
                    access="ROLE_USER" />
                <sec:intercept-url pattern="/web/doctor/**" 
                    access="ROLE_DOCTOR" />
            </sec:filter-security-metadata-source>
        </property>
    </bean>
    <bean id="menuLoaderRequestFilter"
                class="com.saes.security.menu.MenuPermissionsAdapterRequestFilter">
    </bean> 
    <bean id="decisionManager" 
        class="org.springframework.security.access.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false" />
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter"/>
                <ref bean="authenticatedVoter"/>
            </list>
        </property>
    </bean>
    <bean id="roleVoter" 
        class="org.springframework.security.access.vote.RoleVoter" />
    <bean id="authenticatedVoter" 
        class="org.springframework.security.access.vote.AuthenticatedVoter" />
    <bean id="daoAuthenticationProvider" 
        class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService">
            <ref bean="userDetailsService" />
        </property>
    </bean>
    <bean id="anonymousAuthenticationProvider" 
        class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
        <property name="key" value="AD17JFJ005P00Z7MK"/>
    </bean>
    <bean id="authenticationManager"
        class="org.springframework.security.authentication.ProviderManager">
        <property name="providers">
            <list>
                <ref bean="daoAuthenticationProvider" />
                <ref bean="anonymousAuthenticationProvider" />
            </list>
        </property>
    </bean>

flex-servlet.xml:

<flex:message-broker 
        services-config-path="/WEB-INF/config/flex/services-config.xml">
        <flex:secured authentication-manager="authenticationManager"
         access-decision-manager="decisionManager">
            <flex:secured-endpoint-path pattern="**/messagebroker/*" access="ROLE_USER"/>
        </flex:secured>
    </flex:message-broker>

网站.xml:

    <context-param>     
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/config/spring/persistence.xml 
/WEB-INF/config/spring/security.xml
/WEB-INF/config/spring/services.xml
/WEB-INF/config/spring/facade.xml
/WEB-INF/config/spring/validator.xml  
/WEB-INF/config/flex/flex-context.xml                               
    </param-value>
  </context-param>   
  <listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
  </listener>  
  <servlet>     
    <servlet-name>mainServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>  
  <servlet-mapping>
    <servlet-name>mainServlet</servlet-name>
    <url-pattern>/web/*</url-pattern>
  </servlet-mapping>  
  <servlet>     
    <servlet-name>flex</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>  
  <servlet-mapping>
    <servlet-name>flex</servlet-name>
    <url-pattern>/messagebroker/*</url-pattern>
  </servlet-mapping>    
  <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list> 
  <error-page>
    <error-code>500</error-code>    
    <location>/WEB-INF/jsp/errors/critical-error.jsp</location>
  </error-page>  
  <error-page>
    <error-code>404</error-code>    
    <location>/WEB-INF/jsp/errors/404.jsp</location>
  </error-page>

以下是 Flex 代码的相关部分:

<s:ChannelSet id="chatChannelSet">
        <s:StreamingAMFChannel url="http://192.168.1.3:8080/MyApp/messagebroker/streamamf">             
        </s:StreamingAMFChannel>            
    </s:ChannelSet>
    <s:ChannelSet id="remotingChannelSet">
        <s:AMFChannel url="http://192.168.1.3:8080/MyApp/messagebroker/amf">
        </s:AMFChannel>
    </s:ChannelSet>
<s:RemoteObject id="remoteService" 
                    destination="remoteService"
                    channelSet="{remotingChannelSet}">          
    </s:RemoteObject>
var asyncCall:AsyncToken = remoteService.getTicketForCurrentUser();
asyncCall.addResponder(new Responder(getTicket_Result, getTicket_Fault));

前面的代码总是在错误处理程序中结束,并在提示的开头提到错误

其他配置文件:

服务配置.xml:

<services-config> 
<services>       
    <service-include file-path="messaging-config.xml" />        
</services>
<channels>
    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
        <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>
    <channel-definition id="streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
        <endpoint url="http://{server.name}:{server.port}/{context.root}/messagebroker/streamamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
        <properties>
            <idle-timeout-minutes>0</idle-timeout-minutes> 
            <max-streaming-clients>10</max-streaming-clients> 
            <server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis> 
            <user-agent-settings>
                <user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> 
                <user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="3" /> 
            </user-agent-settings>
        </properties>
    </channel-definition>      
</channels>
<logging>
    <target class="flex.messaging.log.ConsoleTarget" level="Debug">
        <properties>
            <prefix>[BlazeDS] </prefix>
            <includeDate>false</includeDate>
            <includeTime>false</includeTime>
            <includeLevel>false</includeLevel>
            <includeCategory>false</includeCategory>
        </properties>
        <filters>
            <pattern>Endpoint.*</pattern>
            <pattern>Service.*</pattern>
            <pattern>Configuration</pattern>
        </filters>
    </target>
</logging>
<system>
    <redeploy>
        <enabled>false</enabled>           
    </redeploy>
</system>

消息配置.xml:

<service id="message-service" 
class="flex.messaging.services.MessageService">
<adapters>
    <adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
</adapters>
<destination id="chat-destination">
    <properties>
        <server>
            <message-time-to-live>0</message-time-to-live>
            <allow-subtopics>true</allow-subtopics>
            <subtopic-separator>.</subtopic-separator>
            <disallow-wildcard-subtopics>true</disallow-wildcard-subtopics>
        </server>           
    </properties>
    <channels>
        <channel ref="streaming-amf" />
    </channels>
</destination>
<default-channels>
    <channel ref="streaming-amf"/>
</default-channels>

在深入研究配置后,我发现了问题,我将为可能需要它的每个人发布解决方案。我必须明确地告诉Spring Security在我的"/messagebroker/**"URL的过滤器链中包含"securityContextPersistenceFilter",以便安全上下文中正确填充身份验证信息(正如我们从一开始就假设的那样)。该配置被添加到"springSecurityFilterChain"bean中,如下所示:

<bean id="springSecurityFilterChain"
    class="org.springframework.security.web.FilterChainProxy">
    <sec:filter-chain-map path-type="ant">
            <!-- other filter chain maps and options here (see the entire file in comment above -->
            <sec:filter-chain 
            filters="securityContextPersistenceFilter" 
            pattern="/messagebroker/**" />
</bean>

将该过滤器链配置添加到 Spring 安全性后,过滤来自 Flex UI 的所有请求,其中自动填充了通过 Spring MVC Web 表单从上次登录创建的现有身份验证。

为了给出一个快速的答案 - 你能把你的 Flex 东西设置成搭载在现有的基于 Spring Security HTML 的登录表单上吗?是的,绝对可以。我已经做到了,如果您有一些应用程序需要保护但无法通过 flex 应用程序提供服务,它的效果非常好。

我没有使用

<flex:secured> 

消息代理配置的一部分(当我第一次设置它时它不存在,也许我现在可以切换到它,但由于我的设置正在工作,我目前不觉得有任何强烈需求)。我已将我的消息代理 URL 模式设置为安全。我的消息代理是安全的,如下所示:

(SWF 加载页面只是包装 SWF 的页面的占位符名称...和 .do 映射到我的视图解析器)

<security:intercept-url pattern="/swf-loading-page.do*" access="ROLE_USER,     
<security:intercept-url pattern="/messagebroker/**" access="ROLE_USER" />

在弹性方面,您调用:

 remoteService.getTicketForCurrentUser()

在 java 端的服务器上调用什么?

对于我的,我做了类似的事情 - 我拉出本地用户将其返回到 flex 客户端(显示当前登录的用户等) -

在Java端,您可以使用SpringSecurityContextHolder获取SecurityContext,然后从SecurityContext中提取

//These packages are where you can hook into the authentication from your service
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
...
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();

如果您是具有jpda调试的应用程序服务器,则可以在该方法上设置断点并查看安全上下文并确保它已正确填充(但似乎不是 - 这很奇怪)

相关内容

  • 没有找到相关文章

最新更新