Pregunta

Soy relativamente nuevo en el Spring Framework y Spring security.

He usado un esquema de autenticación personalizado, HTML:

<form action="j_spring_security_check">
    <input type="text" name="j_username" value="abc"/>
    <input type="text" name="j_password" value="abc"/>
    <input type="text" name="myCustom1" value="pqr"/> <!-- maybe type="hidden" -->
    <input type="text" name="myCustom2" value="pqr"/> <!-- maybe type="hidden" -->
</form>

y el código correspondiente:

public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
{
    @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken)
    throws AuthenticationException
    {
        System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated());
    }

    @Override protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication)
    throws AuthenticationException
    {
        System.out.println("Method invoked : retrieveUser");
        //I have Username,password:
        //HOW CAN I ACCESS "myCustom1", "myCustom2" here ?
    }
}
¿Fue útil?

Solución

Si necesita utilizar parámetros de formulario adicionales para manipular el nombre de usuario y la contraseña, puede implementar su propio AuthenticationProcessingFilter

http: / /static.springsource.org/spring-security/site/apidocs/org/springframework/security/ui/webapp/AuthenticationProcessingFilter.html

Esta clase tendrá acceso completo a HttpRequest y, por lo tanto, a todos los parámetros adicionales que envíe. Si su objetivo es utilizar de alguna manera estos valores para modificar el nombre de usuario y la contraseña, aquí es donde lo haría.

Otros consejos

Todo lo anterior son excelentes y perfectas soluciones. Pero he usado un tipo de solución alternativa que funciona perfectamente bien. Identificación de múltiples inquilinos usada para ThreadLocal

package com.mypackage.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.springframework.util.Assert;

public class ThreadLocalContextUtil implements Filter{
     private static final ThreadLocal<Object> contextHolder =
                new ThreadLocal<Object>();

       public static void setTenantId(Object tenantId) {
          Assert.notNull(tenantId, "customerType cannot be null");
          contextHolder.set(tenantId);
       }

       public static Object getTenantId() {
          return contextHolder.get();
       }

       public static void clearTenant() {
          contextHolder.remove();
       }

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // Set the tenant Id into a ThreadLocal object
        ThreadLocalContextUtil.setTenantId(request);
        if(chain != null)
            chain.doFilter(request, response);
        else {
            //error
        }
    }

    public void init(FilterConfig filterconfig) throws ServletException {

    }
}

Spring Security xml     

<security:http auto-config="true" use-expressions="true" access-denied-page="/forms/auth/403" >
    <security:custom-filter before="FIRST" ref="tenantFilter" />
    ......
    </security:http>

Objeto de solicitud de acceso en su clase de autenticación

HttpServletRequest currRequest = (HttpServletRequest) ThreadLocalContextUtil.getTenantId();

Luego use el objeto de solicitud para obtener sus parámetros personalizados

El truco aquí es que necesita crear un nuevo AuthenicationToken (tal vez) extendiendo UsernameAndPasswordAuthenicationToken y como @emills dice que necesita implementar un nuevo AuthenciationProcessingFilter para asignar los valores de solicitud al token y enviarlos al AuthenicationManager.

Básicamente, hay un par de partes para implementar una cadena de autenticación personalizada en Spring-Security

  • AuthenicationToken : detalles de la solicitud de autenticación y su resultado, es decir, contiene las credenciales que necesita para autenticarse
  • AuthenicationProvider : registrado en AuthenicationManager, acepta su AuthenicationToken y valida al usuario y devuelve un token con el conjunto de autoridades otorgado
  • AuthenciationFilter : en realidad no tiene que ser un filtro, solo usar AbstractProcessingFilter hará que su vida sea un poco más fácil

Yo iría de esta manera:

<bean id="authenticationProcessingFilter"  
    class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  ...
  <property name="authenticationDetailsSource">
    <bean class="org.acegisecurity.ui.AuthenticationDetailsSourceImpl">
        <property name="clazz"  
           value="com.MyAuthenticationDetails"/>
    </bean>
  </property>
</bean>  

Esta es la clase que contiene las propiedades:

package com;
import javax.servlet.http.HttpServletRequest;
import org.acegisecurity.ui.WebAuthenticationDetails;
public class MyAuthenticationDetails extends WebAuthenticationDetails {
    public MyAuthenticationDetails() {
      super();
    }
    //This constructor will be invoqued by the filter
    public MyAuthenticationDetails(HttpServletRequest request) {
        super(request);
        this.myCustom1 = request.getParameter("myCustom1");
    }
    public String getMyCustom1() {
        return myCustom1;
    }
    private String myCustom1;
}

Ahora tiene el nombre de usuario, la contraseña y los detalles.

He hecho algo similar, pero diferente de lo que cualquiera ha sugerido aquí. No estoy diciendo que este sea el "correcto". manera de hacerlo, pero me funcionó muy bien. En el objeto Principal está el usuario y también hay un objeto Detalles en AuthenticationToken que puede almacenar un Mapa (Cadena, Cadena) de otra información de inicio de sesión.

public class RequestFormDeatils extends SpringSecurityFilter {

   protected void doFilterHttp(HttpServletRequest request, ...) {
      SecurityContext sec = SecurityContextHolder.getContent();
      AbstractAuthenticationToken auth = (AbstractAuthenticationToken)sec.getAuthentication();
      Map<String, String> m = new HashMap<String, String>;
      m.put("myCustom1", request.getParamtere("myCustom1"));
      m.put("myCustom2", request.getParameter("myCustom2"));
      auth.setDetails(m);
}

Ahora, en cualquier parte de su código, puede usar el SecurityContext para propagar esta información relacionada con la seguridad sin tener que acoplarla a su objeto UserDetails o pasarla como argumentos. Hago este código en un SecurityFilter al final de la cadena Spring Security Filter.

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean> 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top