with tutorial example español java authentication forms-authentication spring-security

java - tutorial - Configurar Spring Security 3.x para tener múltiples puntos de entrada



spring security rest token authentication (4)

He estado utilizando Spring Security 3.x para manejar la autenticación de usuario para mis proyectos, y hasta ahora, ha funcionado perfectamente.

Recientemente recibí los requisitos para un nuevo proyecto. En este proyecto, requiere 2 juegos de autenticación de usuario: uno para autenticar a los empleados contra LDAP y otro para autenticar al cliente contra la base de datos. Estoy un poco perplejo sobre cómo configurar eso en Spring Security.

Mi idea inicial fue crear una pantalla de inicio de sesión que tenga los siguientes campos:

  • botón de selección de campo - para que los usuarios elijan si son empleados o clientes.
  • j_username user field.
  • j_password contraseña campo.

Si el usuario selecciona "empleado", quiero que Spring Security los autentique contra LDAP; de lo contrario, la credencial se autenticará contra la base de datos. Sin embargo, el problema es que el formulario se enviará a /j_spring_security_check y no hay forma de que envíe el campo del botón de /j_spring_security_check a mi proveedor de autenticación personalizado implementado. Mi idea inicial es que probablemente necesite dos URL de envío de formularios en lugar de confiar en la /j_spring_security_check predeterminada. Cada URL será manejada por diferentes proveedores de autenticación, pero no estoy seguro de cómo configurar eso en Spring Security.

Sé que en Spring Security puedo configurar la autenticación fallida, por ejemplo, si falla la autenticación LDAP, se recurrirá a la autenticación de bases de datos, pero esto no es lo que estoy buscando en este nuevo proyecto.

¿Alguien puede compartir cómo exactamente debo configurar esto en Spring Security 3.x?

Gracias.

ACTUALIZACIÓN - 28/01/2011 - La técnica de @ EasyAngel

Estoy tratando de hacer lo siguiente:

  • El formulario de ingreso del empleado se envía a /j_spring_security_check_for_employee
  • El formulario de cliente ingresa a /j_spring_security_check_for_customer

La razón por la que deseo 2 inicios de sesión de formularios diferentes es permitirme manejar la autenticación de manera diferente en función del usuario, en lugar de realizar una autenticación de recuperación. Es posible que el empleado y el cliente tengan la misma identificación de usuario, en mi caso.

Incorporé la idea de @ EasyAngel, pero tengo que reemplazar algunas clases en desuso. El problema al que me enfrento actualmente es que ni los procesos de filtrado URL parecen estar registrados en Spring Security porque sigo obteniendo el Error 404: SRVE0190E: File not found: /j_spring_security_check_for_employee . Mi instinto me springSecurityFilterChain bean springSecurityFilterChain no está bien conectado, por lo tanto, mis filtros personalizados no se utilizan en absoluto.

Por cierto, estoy usando WebSphere y tengo com.ibm.ws.webcontainer.invokefilterscompatibility=true propiedad com.ibm.ws.webcontainer.invokefilterscompatibility=true establecida en el servidor. Puedo presionar /j_spring_security_check sin problema.

Aquí está mi configuración de seguridad completa: -

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

Estoy comenzando una recompensa aquí porque parece que ya no puedo hacer funcionar esto por varios días ... la palabra es frustración. Espero que alguien señale los problemas, o si puede mostrarme una forma mejor o más limpia de manejar esto (en el código).

Estoy usando Spring Security 3.x.

Gracias.

ACTUALIZACIÓN 29/01/2011 - La técnica de @ Ritesh

De acuerdo, logré que el enfoque de @ Ritesh funcionara muy de cerca con lo que quería. Tengo el botón de radio que permite al usuario seleccionar si son clientes o empleados. Parece que este enfoque funciona bastante bien, con un problema ...

  • Si el empleado inicia sesión con la credencial correcta, se le permite ... TRABAJAR COMO SE ESPERABA .
  • Si el empleado inicia sesión con una credencial incorrecta, no se les permite ... TRABAJAR COMO SE ESPERABA .
  • Si el cliente inicia sesión con la credencial correcta, se le permite ... TRABAJAR COMO SE ESPERABA .
  • Si el cliente inicia sesión con una credencial incorrecta, la autenticación vuelve a la autenticación del empleado ... NO FUNCIONA . Esto es arriesgado porque si selecciono la autenticación del cliente y le pongo la credencial del empleado, también permitirá al usuario entrar y esto no es lo que quiero.

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

Aquí está mi configuración actualizada. Tiene que ser una pequeña modificación que deba hacer para evitar que la autenticación retroceda pero parece que no puedo resolverlo ahora.

Gracias.

ACTUALIZACIÓN - SOLUCIÓN a la técnica de @ Ritesh

De acuerdo, creo que he resuelto el problema aquí. En lugar de tener EmployeeCustomAuthenticationProvider para confiar en el UsernamePasswordAuthenticationToken predeterminado, creé EmployeeUsernamePasswordAuthenticationToken para él, al igual que el que creé CustomerUsernamePasswordAuthenticationToken para CustomerCustomAuthenticationProvider . Estos proveedores anularán los supports() :

Clase CustomerCustomAuthenticationProvider

@Override public boolean supports(Class<? extends Object> authentication) { return (CustomerUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); }

Clase EmployeeCustomAuthenticationProvider

@Override public boolean supports(Class<? extends Object> authentication) { return (EmployeeUsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication)); }

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

... y WALAA! ¡Funciona perfectamente ahora después de varios días de frustración!

Con suerte, este post podrá ayudar a alguien que esté haciendo lo mismo que yo aquí.


No es necesario crear /j_spring_security_check_for_employee y /j_security_check_for_customer filterProcessingUrl .

El predeterminado funcionará perfectamente con la idea de campo del botón de opción.

En el inicio de sesión personalizado de LoginFilter , debe crear diferentes tokens para empleado y cliente.

Estos son los pasos:

  1. Use el nombre de UsernamePasswordAuthenticationToken predeterminado UsernamePasswordAuthenticationToken para el inicio de sesión del empleado.

  2. Crear CustomerAuthenticationToken para iniciar sesión como cliente. Extienda AbstractAuthenticationToken para que su tipo de clase sea distinto de UsernamePasswordAuthenticationToken .

  3. Definir un filtro de inicio de sesión personalizado:

    <security:http> <security:custom-filter position="FORM_LOGIN_FILTER" ref="customFormLoginFilter" /> </security:http>

  4. En customFormLoginFilter , anule attemptAuthentication siguiente manera (pseudo código):

    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. La anulación supports método en EmployeeCustomAuthenticationProvider para admitir UsernamePasswordAuthenticationToken .

  6. La anulación supports método en CustomerCustomAuthenticationProvider para admitir CustomerAuthenticationToken .

    @Override public boolean supports(Class<?> authentication) { return (CustomerAuthenticationToken.class.isAssignableFrom(authentication)); }

  7. Use ambos proveedores en authentication-manager :

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


Puede almacenar esta información en DB. Por ejemplo, puede tener una columna llamada ldap_auth en la tabla Users . Puedes ver mi otra respuesta (como un ejemplo):

Ejemplo de formulario de inicio de sesión Spring

Si observa cuidadosamente la clase UserService , notará que realmente UserService esta bandera LDAP y tomo la contraseña de usuario de LDAP o de la base de datos.


Puede definir varios filtros AuthenticationProcessingFilter . Cada uno de ellos puede tener una URL diferente como / j_security_check_for_employee y / j_security_check_for_customer . Aquí hay un ejemplo del contexto de la aplicación de seguridad que demuestra esta 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>

Como puede ver, en este escenario también tiene diferentes UserDetailService s - para DB auth y LDAP.

Creo que es una buena idea tener diferentes URL de autenticación para clientes y empleados (especialmente si usan diferentes estrategias de autenticación). Incluso puede tener diferentes páginas de inicio de sesión para ellos.


soy yo otra vez :) ¿Puedes tratar de usar filtros como este?

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

en lugar de definir bean springSecurityFilterChain .