configurationSpring Security 3.x有多个入口点
我一直在使用Spring Security 3.x来处理我的项目的用户身份validation,到目前为止,它已经完美运行。
我最近收到了一个新项目的要求。 在这个项目中,需要两套用户authentication:一种是针对LDAPauthentication员工,另一种是针对数据库authentication客户。 我有点难以理解如何在Spring Security中进行configuration。
我最初的想法是创build一个有以下领域的login屏幕: –
- 单选button字段 – 供用户select是员工还是客户。
-
j_username
用户字段。 -
j_password
密码字段。
如果用户select“员工”,那么我希望Spring Security根据LDAP对他们进行身份validation,否则证书将根据数据库进行身份validation。 但是,问题是表单将被提交给/j_spring_security_check
并且我无法将单选button字段发送给我实现的自定义身份validation提供程序。 我最初的想法是我可能需要两个表单提交url,而不是依靠默认的/j_spring_security_check
。 每个URL将由不同的身份validation提供程序处理,但是我不确定如何在Spring Security中configuration它。
我知道在Spring Security中,我可以configuration回退身份validation,例如,如果LDAP身份validation失败,那么它将回退到数据库身份validation,但这不是我在这个新项目中拍摄的内容。
有人可以分享如何在Spring Security 3.x中configuration它吗?
谢谢。
更新 – 01-28-2011 – @ EasyAngel的技术
我正在努力做到以下几点:
- 员工表单login提交给
/j_spring_security_check_for_employee
- 客户表单login提交给
/j_spring_security_check_for_customer
我想要2种不同的表单login的原因是允许我根据用户不同的方式处理authentication,而不是做回退authentication。 就我而言,员工和客户可能有相同的用户ID。
我并入了@ EasyAngel的想法,但必须replace一些弃用的类。 我目前面临的问题是没有筛选进程URLS似乎注册在Spring安全,因为我不断收到Error 404: SRVE0190E: File not found: /j_spring_security_check_for_employee
。 我的直觉是springSecurityFilterChain
bean没有正确连线,因此我的自定义filter根本没有使用。
顺便说一下,我正在使用WebSphere,并且在服务器中设置了com.ibm.ws.webcontainer.invokefilterscompatibility=true
属性。 我能够毫无问题地打到默认的/j_spring_security_check
。
这是我完整的安全configuration:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:sec="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <sec:http auto-config="true"> <sec:form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" default-target-url="/welcome.jsp" always-use-default-target="true" /> <sec:logout logout-success-url="/login.jsp" /> <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" /> <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" /> <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" /> </sec:http> <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> <sec:filter-chain-map path-type="ant"> <sec:filter-chain pattern="/**" filters="authenticationProcessingFilterForEmployee, authenticationProcessingFilterForCustomer" /> </sec:filter-chain-map> </bean> <bean id="authenticationProcessingFilterForEmployee" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManagerForEmployee" /> <property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" /> </bean> <bean id="authenticationProcessingFilterForCustomer" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManagerForCustomer" /> <property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" /> </bean> <bean id="authenticationManagerForEmployee" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <ref bean="employeeCustomAuthenticationProvider" /> </list> </property> </bean> <bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <ref bean="customerCustomAuthenticationProvider" /> </list> </property> </bean> <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.EmployeeUserDetailsService"/> </property> </bean> <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.CustomerUserDetailsService"/> </property> </bean> <sec:authentication-manager> <sec:authentication-provider ref="employeeCustomAuthenticationProvider" /> <sec:authentication-provider ref="customerCustomAuthenticationProvider" /> </sec:authentication-manager> </beans>
我在这里开始赏金,因为我似乎已经好几天没有得到这个工作了……这个词是令人沮丧的。 我希望有人会指出这个问题,或者如果你能给我一个更好或更清洁的方式来处理这个(在代码中)。
我正在使用Spring Security 3.x.
谢谢。
更新01-29-2011 – @ Ritesh的技术
好吧,我设法让@ Ritesh的方法非常紧密地工作,以我想要的。 我有单选button,允许用户select他们是客户还是员工。 看来这种方法工作得很好,有一个问题…
- 如果员工使用正确的凭证login,则允许他们进入…按预期工作 。
- 如果员工使用错误凭证login,则不允许他们进入…按预期工作 。
- 如果客户使用正确的凭证login,则允许他们进入…按预期工作 。
- 如果客户使用错误的凭据login,则authentication会退回到员工身份validation… 不起作用 。 这是有风险的,因为如果我select了客户authentication,并将其打入员工证书,它也将允许用户,而这不是我想要的。
<sec:http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint"> <sec:logout logout-success-url="/login.jsp"/> <sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE"/> <sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER"/> <sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <sec:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthenticationFilter"/> </sec:http> <bean id="myAuthenticationFilter" class="ss.MyAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"/> <property name="authenticationFailureHandler" ref="failureHandler"/> <property name="authenticationSuccessHandler" ref="successHandler"/> </bean> <bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp"/> </bean> <bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <property name="defaultTargetUrl" value="/welcome.jsp"/> <property name="alwaysUseDefaultTargetUrl" value="true"/> </bean> <bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/login.jsp?login_error=1"/> </bean> <bean id="employeeCustomAuthenticationProvider" class="ss.EmployeeCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.EmployeeUserDetailsService"/> </property> </bean> <bean id="customerCustomAuthenticationProvider" class="ss.CustomerCustomAuthenticationProvider"> <property name="userDetailsService"> <bean class="ss.CustomerUserDetailsService"/> </property> </bean> <sec:authentication-manager alias="authenticationManager"> <sec:authentication-provider ref="customerCustomAuthenticationProvider"/> <sec:authentication-provider ref="employeeCustomAuthenticationProvider"/> </sec:authentication-manager> </beans>
这是我更新的configuration。 我需要做一些非常小的调整,以防止身份validation倒退,但现在我似乎无法弄清楚。
谢谢。
更新 – 解决scheme@ Ritesh的技术
好的,我想我已经解决了这个问题。 而不是让EmployeeCustomAuthenticationProvider
依赖于默认的UsernamePasswordAuthenticationToken
,我为它创build了EmployeeUsernamePasswordAuthenticationToken
,就像为CustomerCustomAuthenticationProvider
创buildCustomerCustomAuthenticationProvider
。 这些提供程序将覆盖supports()
: –
CustomerCustomAuthenticationProvider类
@Override public boolean supports(Class<? extends Object> authentication) { return (CustomerUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); }
EmployeeCustomAuthenticationProvider类
@Override public boolean supports(Class<? extends Object> authentication) { return (EmployeeUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); }
MyAuthenticationFilter类
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { ... UsernamePasswordAuthenticationToken authRequest = null; if ("customer".equals(request.getParameter("radioAuthenticationType"))) { authRequest = new CustomerUsernamePasswordAuthenticationToken(username, password); } else { authRequest = new EmployeeUsernamePasswordAuthenticationToken(username, password); } setDetails(request, authRequest); return super.getAuthenticationManager().authenticate(authRequest); }
…和WALAA! 它经过几天的挫折后,现在完美的工作!
希望这篇文章能够帮助那些和我在这里一样的人。
您不需要创build/j_security_check_for_customer
和/j_security_check_for_customer
filterProcessingUrl
。
默认的一个将工作得很好,单选button领域的想法。
在自定义loginLoginFilter
,您需要为员工和客户创build不同的令牌。
这里是步骤:
-
使用默认的
UsernamePasswordAuthenticationToken
进行员工login。 -
为客户login创build
CustomerAuthenticationToken
。 扩展AbstractAuthenticationToken
,使其类types与UsernamePasswordAuthenticationToken
不同。 -
定义一个自定义loginfilter:
<security:http> <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" /> </security:http>
-
在
customFormLoginFilter
,如下所示覆盖attemptAuthentication
(伪代码):if (radiobutton_param value employee) { UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); setDetails(whatever); return getAuthenticationManager().authenticate(authRequest); } else if (radiobutton_param value customer) { CustomerAuthenticationToken authRequest = new CustomerAuthenticationToken(username, password); setDetails(whatever); return getAuthenticationManager().authenticate(authRequest); }
-
Override
supports
EmployeeCustomAuthenticationProvider
方法来支持UsernamePasswordAuthenticationToken
。 -
Override
supports
CustomerCustomAuthenticationProvider
方法来支持CustomerAuthenticationToken
。@Override public boolean supports(Class<?> authentication) { return (CustomerAuthenticationToken.class.isAssignableFrom(authentication)); }
-
在
authentication-manager
使用这两个提供者:<security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref='employeeCustomAuthenticationProvider ' /> <security:authentication-provider ref='customerCustomAuthenticationProvider ' /> </security:authentication-manager>
您可以定义几个AuthenticationProcessingFilter
filter。 它们中的每一个都可以具有不同的URL,如/ j_security_check_for_employee和/ j_security_check_for_customer 。 下面是安全应用程序上下文的例子,它演示了这个想法:
<bean id="myfilterChainProxy" class="org.springframework.security.util.FilterChainProxy"> <security:filter-chain-map pathType="ant"> <security:filter-chain pattern="/**" filters="authenticationProcessingFilterForCustomer, authenticationProcessingFilterForEmployee, ..." /> </security:filter-chain-map> </bean> <bean id="authenticationProcessingFilterForCustomer" class="org.springframework.security.web.authentication.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManagerForCustomer"/> <property name="filterProcessesUrl" value="/j_security_check_for_customer"/> </bean> <bean id="authenticationProcessingFilterForEmployee" class="org.springframework.security.web.authentication.AuthenticationProcessingFilter"> <property name="authenticationManager" ref="authenticationManagerForEmployee"/> <property name="filterProcessesUrl" value="/j_security_check_for_employee"/> </bean> <bean id="authenticationManagerForCustomer" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider"> <property name="userDetailsService"> <ref bean="customerUserDetailsServiceThatUsesDB"/> </property> </bean> </list> </property> </bean> <bean id="authenticationManagerForEmployee" class="org.springframework.security.authentication.ProviderManager"> <property name="providers"> <list> <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"> <property name="userDetailsService"> <ref bean="employeeUserDetailsServiceThatUsesLDAP"/> </property> </bean> </list> </property> </bean>
正如你所看到的,在这种情况下,你也有不同的UserDetailService
– 用于数据库身份validation和LDAP。
我认为为客户和员工提供不同的身份validationURL是一个好主意(特别是如果他们使用不同的身份validation策略)。 你甚至可以有不同的login页面。
您可以将此信息存储在数据库中。 例如,你可以在Users
表中有一个名为ldap_auth
列。 你可以看看我的其他答案(作为一个例子):
Springlogin表单示例
如果你仔细看看UserService
类,你会注意到,我实际上testing了这个LDAP标志,并从LDAP或数据库中获取用户密码。
这是我再次:)你可以尝试使用这样的filter:
<sec:http auto-config="true"> ... <sec:custom-filter ref="authenticationProcessingFilterForCustomer" after="FIRST"/> <sec:custom-filter ref="authenticationProcessingFilterForEmployee" after="FIRST"/> </sec:http>
而不是定义bean springSecurityFilterChain
。
- 如何做无状态(无会话)和无cookie的身份validation?
- 扩展Devise SessionsController以使用JSON进行身份validation
- 如何在全新安装后login并validationPostgresql?
- JWT(JSON Web令牌)自动延长到期
- 身份validation2个不同的表
- HttpURLConnection在Android 2.x中工作正常,但在4.1中没有:没有发现身份validation的挑战
- 在GitHub API上使用带有用户名和密码的Invoke-WebRequest进行基本authentication
- REST API授权和authentication(网页+手机)
- 如何创build基本身份validation的用户帐户?