положение, но кажется, что это неправильно).

ользую 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's техника

Я пытаюсь сделать следующее: -

Форма входа сотрудника/j_spring_security_check_for_employeeФорма входа для клиента/j_spring_security_check_for_customer

Причина, по которой я хочу иметь два разных входа в систему, заключается в том, что я могу по-разному обрабатывать аутентификацию в зависимости от пользователя, а не выполнять резервную аутентификацию. Возможно, у сотрудника и клиента одинаковый идентификатор пользователя, в моем случае.

Я включил идею @ EasyAngel, но должен заменить некоторые устаревшие классы. Проблема, с которой я сейчас сталкиваюсь, заключается в том, что ни один из процессов фильтрации не выглядит зарегистрированным в Spring Security, посколькуError 404: SRVE0190E: File not found: /j_spring_security_check_for_employee, Мое внутреннее чувствоspringSecurityFilterChain bean не подключен должным образом, поэтому мои пользовательские фильтры не используются вообще.

Кстати, я использую 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 работать очень близко к тому, что я хотел. У меня есть кнопка радио, которая позволяет пользователю выбирать, являются ли они клиентом или сотрудником. Кажется, что этот подход работает довольно хорошо, с одной проблемой ...

Если сотрудник входит с правильными учетными данными, они могут ...РАБОТАЙТЕ, КАК ОЖИДАЕТСЯ.Если сотрудник входит в систему с неправильными учетными данными, они не могут ...РАБОТАЙТЕ, КАК ОЖИДАЕТСЯ.Если клиент входит в систему с правильными учетными данными, они могут ...РАБОТАЙТЕ, КАК ОЖИДАЕТСЯ.Если клиент входит в систему с неверными учетными данными, аутентификация возвращается к аутентификации сотрудника ...НЕ РАБОТАЕТ, Это рискованно, потому что, если я выберу аутентификацию клиента и введу учетные данные сотрудника, это тоже позволит пользователю войти, а это не то, чего я хочу.
    <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

@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);
}

... и ВАЛАА! Теперь он отлично работает после нескольких дней разочарования!

Надеюсь, этот пост сможет помочь кому-то, кто делает то же самое, что и я здесь.

 Ritesh29 янв. 2011 г., 23:51
Вы также можете предотвратить откат, выбрасывая исключение от провайдера и перехватывая его в фильтре. К следующему поставщику в цепочке обращаются только тогда, когда поставщик возвращает ноль.
 bluish15 янв. 2015 г., 15:18
@limc Опубликуйте свое решение в качестве ответа и примите его, если хотите. Таким образом, люди сразу увидят, какое решение есть. ;)
 limc30 янв. 2011 г., 00:24
@ritesth: спасибо! Я думаю, что у меня ограниченные знания о Spring Security, и все это время я использовал самую простую и понятную конфигурацию, но я не могу сделать то же самое для этого нового проекта. Но это хороший учебный опыт, несмотря на всю боль, которую я пережил. :) На данный момент, я думаю, что я предпочитаю использоватьsupport() вместо того, чтобы бросать исключение от провайдера, потому что я чувствую, что это более чистый подход.

Ответы на вопрос(4)

) Можете ли вы попробовать использовать фильтры вот так:

<sec:http auto-config="true">
    ...
    <sec:custom-filter ref="authenticationProcessingFilterForCustomer" after="FIRST"/>
    <sec:custom-filter ref="authenticationProcessingFilterForEmployee" after="FIRST"/>
</sec:http>

вместо определения бобовspringSecurityFilterChain.

 limc28 янв. 2011 г., 22:39
Я поставилauto-config вfalse и я все еще получаю эту ошибку. Я думаю, что это потому, что как сотрудники, так и клиенты используютUsernamePasswordAuthenticationFilter, Я попытался создать свой собственный фильтр, который расширяет этот фильтр, и я тоже получаю ту же ошибку.
 limc28 янв. 2011 г., 22:37
Я закомментировалspringSecurityFilterChain и добавить, что 2 строки, и я получаю следующие ошибки:Configuration problem: Filter beans '<authenticationProcessingFilterForEmployee>' and '<authenticationProcessingFilterForCustomer>' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from <http> and avoiding the use of <http auto-config='true'>.
 tenshi28 янв. 2011 г., 23:00
Вы можете изменить первый тег на<sec:custom-filter ref="authenticationProcessingFilterForCustomer" position="FIRST"/> (position вместоafter)
 limc29 янв. 2011 г., 20:16
все та же ошибка.
 tenshi29 янв. 2011 г., 21:13
хм ... странно ... посмотрел на корреспондентаBeanDefinitionParser и выяснил, что порядок фильтра там назначен. По данным XSD (springframework.org/schema/security/spring-security-3.1.xsd) вы можете разместить фильтры вposition, before, or after некоторый именованный фильтр (возможные значения можно найти в simpleTypenamed-security-filter). Чтобы заставить его работать, вы можете попробовать поместить эти 2 фильтра в (или до / после) в разные именованные фильтры (я разместил их обаFIRST положение, но кажется, что это неправильно).
Решение Вопроса

/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);
}

Overridesupports метод вEmployeeCustomAuthenticationProvider поддерживатьUsernamePasswordAuthenticationToken.

Overridesupports метод в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>
 limc29 янв. 2011 г., 21:10
Я даю вам +1 здесь, чтобы указать мне правильное направление. У меня есть одна проблема с вашим подходом относительно резервной аутентификации. Я обновил свой пост выше с вашим именем на нем.
 limc29 янв. 2011 г., 18:45
Спасибо за ваш ответ. ЛиcustomFormLoginFilter простиратьсяUsernamePasswordAuthenticationFilter? Боюсь, что этот фильтр реализуетUsernamePasswordAuthenticationFilterЯ получу исключение «два фильтра в одном порядке», как описано в моем ответе на @EasyAngel. Можете ли вы объяснить, почему № 6 необходимо переопределитьsupport() но № 5 не нужно?
 limc29 янв. 2011 г., 21:24
Я решил проблему. В любом случае, я буду награждать вас премией +50, +1 и галочкой, это максимально возможное количество баллов, которые я могу вам дать за помощь. Огромное спасибо.

вы можете иметь столбец с именемldap_auth вUsers Таблица. Вы можете посмотреть на мой другой ответ (в качестве примера):

Пример формы входа в Spring

Если вы внимательно посмотрите наUserService класс, вы заметите, что я на самом деле проверяю этот флаг LDAP и беру пароль пользователя из LDAP или базы данных.

 tenshi25 янв. 2011 г., 20:18
Кажется, что ваши требования более ограничены, чем я думал. У меня есть другая идея, но я добавил ее как отдельный ответ, потому что она сильно отличается от текущей. Надеюсь это поможет...
 limc25 янв. 2011 г., 01:29
сотрудники хранятся в LDAP, но меня беспокоит, что возможно (в редких случаях), что идентификатор пользователя клиента (например, john01) совпадает с идентификатором пользователя сотрудника (например, john01), даже если они представляют двух разных людей.
 limc24 янв. 2011 г., 15:50
Что если идентификатор пользователя сотрудника совпадает с идентификатором пользователя клиента? Это может произойти для этого конкретного проекта. В этом случае этот сотрудник никогда не будет аутентифицирован по LDAP.
 tenshi24 янв. 2011 г., 16:00
То есть у вас есть одна и та же запись БД для сотрудника и клиента? или вся информация о сотрудниках хранится в LDAP?

Вы можете определить несколько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>

Как видите, в этом сценарии у вас также есть разныеUserDetailServices - для аутентификации БД и LDAP.

Я думаю, что было бы неплохо иметь разные аутентификационные URL-адреса для клиентов и сотрудников (особенно, если они используют разные стратегии аутентификации). Вы даже можете иметь разные страницы входа для них.

 We are Borg20 янв. 2015 г., 13:39
Здравствуйте, я использую ваш метод аналогичным образом, но у меня возникают ошибки преобразования типов, пожалуйста, проверьте это сообщение:stackoverflow.com/questions/28041310/...
 tenshi28 янв. 2011 г., 02:03
да, так и будет, но поскольку у них разные URL,authenticationProcessingFilterForEmployee не будет использоваться, и имеет место только один механизм аутентификации.
 tenshi28 янв. 2011 г., 03:07
1) нет, вweb.xml DelegatingFilterProxy просто делегирует всю необходимую фильтрацию в контекст Spring (обычно она должна быть объявлена ​​только один раз и сопоставлена ​​с/*). 2) легко выйти из системы - все, что вам нужно сделать - сделать сеанс недействительным, например:request.getSession().invalidate() (это полностью не зависит от типа логина)
 limc28 янв. 2011 г., 02:51
Я дал тебе +1 за то, что ты чрезвычайно терпелив со мной здесь. :) Для цепочки фильтров достаточно указать только 2 фильтра обработки аутентификации или мне нужно указать все фильтры, перечисленные вstatic.springsource.org/spring-security/site/docs/3.0.x/...? Другой вопрос, который у меня есть, как мне справиться с выходом из системы как для сотрудника, так и для клиента? Нужно ли мне создавать два logoutFilters и добавлять их в цепочку фильтров? Большое спасибо.
 limc28 янв. 2011 г., 01:36
Извините за мой поздний ответ, что-то догнал ... спасибо за ответ, кстати. У меня есть один вопрос: если вы устанавливаете цепочку фильтров с параметром authenticationProcessingFilterForCustomer, а затем authenticationProcessingFilterForEmployee, если аутентификация клиента не проходит, не откатится ли он к следующему фильтру, который является authenticationProcessingFilterForEmployee? Благодарю.

Ваш ответ на вопрос