여러 진입 점을 갖도록 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
에서 직원과 고객에 대해 서로 다른 토큰을 만들어야합니다.
단계는 다음과 같습니다.
Use default
UsernamePasswordAuthenticationToken
for employee login.Create
CustomerAuthenticationToken
for customer login. ExtendAbstractAuthenticationToken
so that its class type is distinct fromUsernamePasswordAuthenticationToken
.Define a custom login filter:
<security:http> <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" /> </security:http>
In
customFormLoginFilter
, overrideattemptAuthentication
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); }
Override
supports
method inEmployeeCustomAuthenticationProvider
to supportUsernamePasswordAuthenticationToken
.Override
supports
method inCustomerCustomAuthenticationProvider
to supportCustomerAuthenticationToken
.@Override public boolean supports(Class<?> authentication) { return (CustomerAuthenticationToken.class.isAssignableFrom(authentication)); }
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 UserDetailService
s - 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):
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
.
'program tip' 카테고리의 다른 글
Scala Hoogle과 동등합니까? (0) | 2020.11.22 |
---|---|
xcode 8 푸시 알림 기능 및 권한 파일 설정 (0) | 2020.11.22 |
콜백 기반 비동기 메서드를 대기 가능한 작업으로 변환하는 가장 좋은 방법 (0) | 2020.11.22 |
range ()가 Python 3.3의 생성기 인 경우 범위에서 next ()를 호출 할 수없는 이유는 무엇입니까? (0) | 2020.11.21 |
문자열을 변수와 어떻게 연결합니까? (0) | 2020.11.21 |