我在基于 Spring 的应用程序中对用户进行预身份验证时遇到问题。
这是我的场景。我有两个 CustomUserDetailsServices,一个用于员工,一个用于客户。在我的服务器前面,它实现了一个代理,它在客户端请求的 Http Header 中添加了两个标头信息。让我们称他们为Header_A
和Header_B
。
我希望 Spring Security 执行以下步骤:
- 取
Header_A
并在 , 中使用它EmployeeUserDetailsService
来调用loadUserByUsername(String name)
方法。如果找到用户,则对其进行身份验证并授予他对应用程序的访问权限。 - 如果未找到该用户(未将其标识为员工),我希望该安全性能够获取
Header_B
并在CustomerUserDetailsService
.
我尝试了以下方法,它可以工作,但是有一个变通方法(我不想做那个变通方法):
<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"/>
这件事做了以下事情:
- 获取 Header_A 并在 EmployeeUserDetailsService 中使用它
- 获取 Header_B 并在 EmployeeUserDetailsService 中使用它
- 获取 Header_A 并在 CustomerUserDetailsServie 中使用它
- 获取 Header_B 并在 CustomerUserDetailsServie 中使用它
我所做的解决方法是验证标题的长度(即修复),然后返回;如果一个标头位于错误的 UserDetailsService 中