Настройка Spring Security 3.x иметь несколько точек входа
я использую Spring Security 3.x для обработки аутентификации пользователей для моих проектов, и до сих пор он работал безупречно.
недавно я получил требования к новому проекту. В этом проекте требуется 2 набора аутентификации пользователя: один для аутентификации сотрудников по LDAP, а другой для аутентификации клиента по базе данных. Я немного озадачен тем, как настроить это в Spring Security.
моей первоначальной идеей было создать логин экран, который имеет следующие поля:-
- поле переключателя-для пользователей, чтобы выбрать, являются ли они сотрудниками или клиентами.
-
j_username
поле "пользователь". -
j_password
поле "Пароль".
если пользователь выбирает "сотрудник", то я хочу, чтобы Spring Security аутентифицировал их против LDAP, иначе учетные данные будут аутентифицированы против базы данных. Однако проблема в том, что форма будет отправлена в /j_spring_security_check
и там никакого способа для меня, чтобы отправить в поле, чтобы мое реализован пользовательский поставщик проверки подлинности. Моя первоначальная мысль заключается в том, что мне, вероятно, нужны два URL-адреса отправки формы, а не полагаться на значение по умолчанию /j_spring_security_check
. Каждый URL-адрес будет обрабатываться разными поставщиками аутентификации, но я не уверен, как настроить это в Spring Security.
я знаю, что в Spring Security я могу настроить обратную аутентификацию, например, если аутентификация LDAP не выполняется, то она вернется в базу данных аутентификация, но это не то, что я снимаю в этом новом проекте.
может кто-то поделиться, как именно я должен настроить это в Spring Security 3.x?
спасибо.
обновление - 01-28-2011 - @EasyAngel техника
я пытаюсь сделать следующее:-
- сотрудник форма входа подчиняется
/j_spring_security_check_for_employee
- вход в форму клиента отправляется
/j_spring_security_check_for_customer
причина, по которой я хочу 2 разные формы входа в систему, чтобы позволить мне обрабатывать аутентификацию по-разному на основе пользователя, а не делать резервную аутентификацию. Возможно, что сотрудник и клиент имеют один и тот же идентификатор пользователя, в моем случае.
я включил идею @EasyAngel, но должен заменить некоторые устаревшие классы. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что URL-адреса процессов фильтрации не зарегистрированы в Spring Security, потому что я продолжаю получать Error 404: SRVE0190E: File not found: /j_spring_security_check_for_employee
. Мое чутье-это springSecurityFilterChain
Боб не подключен должным образом, поэтому мои пользовательские фильтры не используются вообще.
кстати, я использую WebSphere и у меня есть com.ibm.ws.webcontainer.invokefilterscompatibility=true
свойство, установленное на сервере. Я могу ударить по умолчанию /j_spring_security_check
без проблем.
вот моя полная конфигурация безопасности: -
<?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 работать очень близко к тому, что я хотел. У меня есть radiobutton, который позволяет пользователю выбрать, являются ли они клиентом или сотрудником. Похоже на такой подход работает довольно хорошо, с одной проблемой...
- если сотрудник входит в систему с правильными учетными данными,они допускаются... РАБОТАТЬ, КАК ОЖИДАЛОСЬ.
- если сотрудник входит в систему с неверными учетными данными,они не допускаются... РАБОТАТЬ, КАК ОЖИДАЛОСЬ.
- если клиент входит в систему с правильными учетными данными,они допускаются... РАБОТАТЬ, КАК ОЖИДАЛОСЬ.
- если клиент входит в систему с неверными учетными данными, то проверка подлинности возвращается к проверке подлинности сотрудника... НЕ РАБОТАЕТ. Это рискованно, потому что если я выберу аутентификацию клиента и пробью его учетные данные сотрудника, это позволит пользователю тоже, и это не то, что я хочу.
<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>
вот моя обновленная конфигурация. Это должна быть какая-то очень маленькая настройка, которую мне нужно сделать, чтобы предотвратить возврат аутентификации, но я не могу понять это сейчас.
спасибо вы.
обновление-решение для техники @Ritesh
хорошо, я думаю, что я решил эту проблему здесь. Вместо EmployeeCustomAuthenticationProvider
полагаться на значение по умолчанию UsernamePasswordAuthenticationToken
, я создал EmployeeUsernamePasswordAuthenticationToken
для него, так же, как тот, который я создал CustomerUsernamePasswordAuthenticationToken
на CustomerCustomAuthenticationProvider
. Затем эти поставщики переопределят supports()
: -
CustomerCustomAuthenticationProvider class
@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 class
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);
}
... и Валаа! Он отлично работает сейчас после нескольких дней разочарования!
надеюсь, этот пост сможет помочь кому-то, кто делает то же самое, что и я здесь.
4 ответа:
вам не нужно создавать
/j_spring_security_check_for_employee
и/j_security_check_for_customer
filterProcessingUrl
.по умолчанию он будет работать просто отлично с идеей поля переключателя.
в пользовательском логине
LoginFilter
, вам нужно создать различные токены для сотрудника и клиента.вот шаги:
использовать по умолчанию
UsernamePasswordAuthenticationToken
для входа сотрудника.создать
CustomerAuthenticationToken
для входа клиента. РасширитьAbstractAuthenticationToken
так что его типа отличается отUsernamePasswordAuthenticationToken
.определите пользовательский фильтр входа:
<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); }
переопределить
supports
методEmployeeCustomAuthenticationProvider
в поддержкуUsernamePasswordAuthenticationToken
.переопределить
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
фильтры. Каждый из них может иметь другой 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
s-для DB auth и LDAP.Я думаю, что это хорошая идея, чтобы иметь различные URL-адреса auth для клиентов и сотрудников (особенно если они используют разные стратегии аутентификации). Вы даже можете иметь различные страницы входа для них.
вы можете хранить эту информацию в БД. Например, вы можете иметь столбец с именем
ldap_auth
наUsers
таблица. Вы можете посмотреть на мой другой ответ (в качестве примера):Если вы внимательно посмотрите на
UserService
класс, вы заметите, что я на самом деле тестирую этот флаг LDAP и беру пароль пользователя либо из LDAP, либо из базы данных.
это я снова :) вы можете попробовать использовать фильтры, как это:
<sec:http auto-config="true"> ... <sec:custom-filter ref="authenticationProcessingFilterForCustomer" after="FIRST"/> <sec:custom-filter ref="authenticationProcessingFilterForEmployee" after="FIRST"/> </sec:http>
вместо определения bean
springSecurityFilterChain
.