spring-security - 如何根据 RequestHeaderAuthenticationFilter 将身份验证管理器委派给特定的 CustomUserDetailsS​​ervice?

标签 spring-security request-headers pre-authentication

我在基于 spring 的应用程序中对用户进行预身份验证时遇到问题。

这是我的场景。我有两个 CustomUserDetailsS​​ervices,一个用于员工,一个用于客户。在我的服务器前面实现了一个代理,它向客户端请求的 Http Header 添加了两个 header 信息。我们称它们为 Header_AHeader_B

我希望 spring security 执行以下步骤:

  1. 获取 Header_A 并在 EmployeeUserDetailsS​​ervice 中使用它,以调用 loadUserByUsername(String name) 方法。如果找到用户,对其进行身份验证并授予他访问该应用程序的权限。
  2. 如果未找到用户(未将其标识为员工),我希望安全获取 Header_B 并在 CustomerUserDetailsS​​ervice 中使用它。

我已经尝试了以下方法,它有效,但有一个变通办法(我不想做那个变通办法):

<sec:http use-expressions="true" access-denied-page="/denied.jsp" entry-point-ref="http403EntryPoint">
    <sec:intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 
    <sec:custom-filter after="PRE_AUTH_FILTER" ref="customerFilter" />
    <sec:custom-filter position="PRE_AUTH_FILTER" ref="employeeFilter" />
    <sec:logout delete-cookies="true" invalidate-session="true" logout-success-url="/" />
</sec:http>
<bean id="employeeFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Header_A"/>
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false"/>
</bean> 
<bean id="customerFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Header_B"/>
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false"/>
</bean>
<bean id="employeePreAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="throwExceptionWhenTokenRejected" value="false" />
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="employeeUserDetailsService"/>
        </bean>
    </property>
</bean>
<bean id="customerPreAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="throwExceptionWhenTokenRejected" value="false" />
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="customerUserDetailsService"/>
        </bean>
    </property>
</bean>
<sec:authentication-manager alias="authenticationManager">
    <sec:authentication-provider ref="employeePreAuthProvider" />
    <sec:authentication-provider ref="customerPreAuthProvider" />
</sec:authentication-manager>    
<bean id="customerUserDetailsService" class="xxx.CustomerUserDetailsService"/>
<bean id="employeeUserDetailsService" class="xxx.EmployeeUserDetailsService"/>

这个东西做了以下事情:

  1. 获取 Header_A 并在 EmployeeUserDetailsS​​ervice 中使用它
  2. 获取 Header_B 并在 EmployeeUserDetailsS​​ervice 中使用它
  3. 获取 Header_A 并在 CustomerUserDetailsS​​ervie 中使用它
  4. 获取 Header_B 并在 CustomerUserDetailsS​​ervie 中使用它

我做的解决方法是验证 header 的长度(即修复),然后返回;如果一个 header 在错误的 UserDetailsS​​ervice 中

最佳答案

如果您只想为 Header_A 使用 EmployeeUserDetailsS​​ervice 并为 Header_B 使用 CustomerUserDetailsS​​ervice,那么您可以创建多个 AuthenticationManager 实例并将它们连接到相应的过滤器中。例如:

<sec:http use-expressions="true" access-denied-page="/denied.jsp" entry-point-ref="http403EntryPoint" authentication-manager-ref="authenticationManager">
    <sec:intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 
    <sec:custom-filter after="PRE_AUTH_FILTER" ref="customerFilter" />
    <sec:custom-filter position="PRE_AUTH_FILTER" ref="employeeFilter" />
    <sec:logout delete-cookies="true" invalidate-session="true" logout-success-url="/" />
</sec:http>
<bean id="employeeFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Header_A"/>
    <property name="authenticationManager" ref="employeeAuthenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false"/>
</bean> 
<bean id="customerFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Header_B"/>
    <property name="authenticationManager" ref="customerAuthenticationManager" />
    <property name="exceptionIfHeaderMissing" value="false"/>
</bean>
<bean id="employeePreAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="throwExceptionWhenTokenRejected" value="false" />
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="employeeUserDetailsService"/>
        </bean>
    </property>
</bean>
<bean id="customerPreAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <property name="throwExceptionWhenTokenRejected" value="false" />
    <property name="preAuthenticatedUserDetailsService">
        <bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
            <property name="userDetailsService" ref="customerUserDetailsService"/>
        </bean>
    </property>
</bean>
<sec:authentication-manager id="authenticationManager">
    <sec:authentication-provider ref="customerPreAuthProvider" />
    <sec:authentication-provider ref="employeePreAuthProvider" />
</sec:authentication-manager>
<sec:authentication-manager id="customerAuthenticationManager">
    <sec:authentication-provider ref="customerPreAuthProvider" />
</sec:authentication-manager>
<sec:authentication-manager id="employeeAuthenticationManager">
    <sec:authentication-provider ref="employeePreAuthProvider" />
</sec:authentication-manager>    
<bean id="customerUserDetailsService" class="xxx.CustomerUserDetailsService"/>
<bean id="employeeUserDetailsService" class="xxx.EmployeeUserDetailsService"/>

一些注意事项:

  • 如示例所示,在 sec:authentication-manager 上使用 id 属性,因为使用别名将覆盖之前的 bean 定义并为其分配另一个指针
  • 如示例所示,确保更新 employeeFilter 和 customerFilter 中的 authenticationManager 引用
  • 如示例所示,确保指定 http@authentication-manager-ref指向可以验证两个用户的 AuthenticationManager 的属性。这对于 FilterSecurityInterceptor 之类的东西是必要的。

关于spring-security - 如何根据 RequestHeaderAuthenticationFilter 将身份验证管理器委派给特定的 CustomUserDetailsS​​ervice?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19687697/

相关文章:

Spring sessionRegistry 给出零个登录用户的列表

c# - 无法在 Rest 请求中添加日期参数(Rest Sharp)

asp.net-mvc - 如何在 ASP.NET MVC 3 Intranet 应用程序中重新验证用户?

react-native - 从需要 header 的 URL react native 图像

java - Spring security PreAuthentication Filter 要求 AuthenticationEntryPoint

java - Spring Security 预身份验证

java - SpEL 中的实例

java - 当已经通过 ldap Spring 3.0 进行身份验证时,如何获取 Active Directory 组?

reactjs - 如何将 Windows 身份验证(浏览器)从 React 应用程序传递到 Spnego Kerberos Spring SSO?

python - 使用 WSGI 访问原始原始 header