program tip

여러 진입 점을 갖도록 Spring Security 3.x 구성

radiobox 2020. 11. 22. 19:18
반응형

여러 진입 점을 갖도록 Spring Security 3.x 구성


내 프로젝트에 대한 사용자 인증을 처리하기 위해 Spring Security 3.x를 사용해 왔으며 지금까지 완벽하게 작동했습니다.

최근에 새 프로젝트에 대한 요구 사항을 받았습니다. 이 프로젝트에서는 두 가지 사용자 인증이 필요합니다. 하나는 LDAP에 대해 직원을 인증하고 다른 하나는 데이터베이스에 대해 고객을 인증합니다. Spring Security에서 구성하는 방법에 대해 약간 난처합니다.

내 초기 아이디어는 다음 필드가있는 로그인 화면을 만드는 것이 었습니다.

  • 라디오 버튼 필드-사용자가 직원인지 고객인지 선택할 수 있습니다.
  • j_username 사용자 필드.
  • j_password 암호 필드.

사용자가 "employee"를 선택하면 Spring Security가 LDAP에 대해 인증하기를 원합니다. 그렇지 않으면 자격 증명이 데이터베이스에 대해 인증됩니다. 그러나 문제는 양식이 제출 될 것이며 /j_spring_security_check구현 된 사용자 지정 인증 공급자에게 라디오 버튼 필드를 보낼 수있는 방법이 없다는 것입니다. 내 초기 생각은 아마도 기본값에 의존하는 대신 두 개의 양식 제출 URL이 필요할 것입니다 /j_spring_security_check. 각 URL은 다른 인증 공급자에 의해 처리되지만 Spring Security에서 구성하는 방법을 잘 모르겠습니다.

저는 Spring Security에서 폴백 인증을 구성 할 수 있다는 것을 알고 있습니다. 예를 들어 LDAP 인증이 실패하면 데이터베이스 인증으로 폴백되지만이 새 프로젝트에서는 이것이 제가 촬영하는 것이 아닙니다.

누군가가 Spring Security 3.x에서 정확히 어떻게 구성해야하는지 공유 할 수 있습니까?

감사합니다.


업데이트-2011 년 1 월 28 일-@EasyAngel의 기술

나는 다음을 시도하고있다 :-

  • 직원 양식 로그인이 제출됩니다. /j_spring_security_check_for_employee
  • 고객 양식 로그인이 제출됩니다. /j_spring_security_check_for_customer

두 가지 다른 양식 로그인을 원하는 이유는 대체 인증을 수행하는 대신 사용자에 따라 인증을 다르게 처리 할 수 ​​있기 때문입니다. 제 경우에는 직원과 고객이 동일한 사용자 ID를 가질 수 있습니다.

@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의 기술

좋아요, 저는 @Ritesh의 접근 방식을 제가 원하는 것과 매우 가깝게 작동하도록 만들었습니다. 사용자가 고객인지 직원인지 선택할 수있는 라디오 버튼이 있습니다. 이 접근 방식은 한 가지 문제가 있지만 상당히 잘 작동하는 것 같습니다.

  • 직원이 올바른 자격 증명으로 로그인하면 다음에서 허용됩니다 . 예상대로 작동 합니다.
  • 직원이 잘못된 자격 증명으로 로그인하는 경우 허용되지 않습니다 ... WORK AS EXPECTED .
  • 고객이 올바른 자격 증명으로 로그인하면 다음에서 허용됩니다 . 예상대로 작동 합니다.
  • 고객이 잘못된 자격 증명으로 로그인하면 인증이 직원 인증으로 대체됩니다 ... 작동하지 않습니다 . 고객 인증을 선택하고 직원 자격 증명을 펀치하면 사용자도 허용 할 수 있으며 이것이 제가 원하는 것이 아니기 때문에 위험합니다.
    <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 클래스

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! 며칠의 좌절 후에 이제 완벽하게 작동합니다!

바라건대,이 포스트가 제가 여기있는 것과 같은 일을하는 누군가를 도울 수 있기를 바랍니다.


/j_spring_security_check_for_employee을 만들 필요가 없습니다 /j_security_check_for_customer filterProcessingUrl.

기본 버튼은 라디오 버튼 필드 아이디어로 잘 작동합니다.

사용자 지정 로그인 LoginFilter에서 직원과 고객에 대해 서로 다른 토큰을 만들어야합니다.

단계는 다음과 같습니다.

  1. Use default UsernamePasswordAuthenticationToken for employee login.

  2. Create CustomerAuthenticationToken for customer login. Extend AbstractAuthenticationToken so that its class type is distinct from UsernamePasswordAuthenticationToken.

  3. Define a custom login filter:

    <security:http>
        <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" />
    </security:http>
    
  4. In customFormLoginFilter, override attemptAuthentication as follows (pseudo code):

    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);
    }
    
  5. Override supports method in EmployeeCustomAuthenticationProvider to support UsernamePasswordAuthenticationToken.

  6. Override supports method in CustomerCustomAuthenticationProvider to support CustomerAuthenticationToken.

    @Override
    public boolean supports(Class<?> authentication) {
        return (CustomerAuthenticationToken.class.isAssignableFrom(authentication));
    }
    
  7. Use both providers in authentication-manager:

    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref='employeeCustomAuthenticationProvider ' />
        <security:authentication-provider ref='customerCustomAuthenticationProvider ' />
    </security:authentication-manager>
    

You can define several AuthenticationProcessingFilter filters. Each of them can have different URL like /j_security_check_for_employee and /j_security_check_for_customer. Here is example of the security application context that demonstrates this idea:

<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>

As you can see, in this scenario you have also different UserDetailServices - for DB auth and LDAP.

I think it's good idea to have different auth URLs for customers and employee (especially if they use different authentication strategies). You can even have different login pages for them.


For Java Configuration reference

As i keen to write here java configuration way of implementing the same technique to help people who is not familiar with xml configuration but i don't want to hijack this thread beauty with such a long answer of java configuration code.

People who wants to achieve the same with java configuration(Annotation based) can refer my self answered question link is given below and also you can find my github repository link for the code in the answer.

For Annotation based configuration code refer Multiple AuthenticationProvider with different UsernamePasswordAuthToken to authenticate different login forms without fallback authentication


You can store this information in DB. For example you can have column called ldap_auth in Users table. You can look at my other answer (as an example):

Spring login form example

If you carefully look at UserService class, you will notice, that I actually test this LDAP flag and take user password either from LDAP or database.


it's me again :) Can you try to use filters like this:

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

instead of defining bean springSecurityFilterChain.

참고URL : https://stackoverflow.com/questions/4783063/configuring-spring-security-3-x-to-have-multiple-entry-points

반응형