Est-il possible d'envoyer plus de données dans une authentification basée sur un formulaire dans Spring?

StackOverflow https://stackoverflow.com/questions/1629273

Question

Les Spring Framework et la sécurité de Spring sont relativement nouveaux.

J'ai utilisé un schéma d'authentification personnalisé, 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>

et le code correspondant:

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 ?
    }
}
Était-ce utile?

La solution

Si vous devez utiliser des paramètres de formulaire supplémentaires pour manipuler le nom d'utilisateur et le mot de passe, vous pouvez implémenter votre propre AuthenticationProcessingFilter

.

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

Cette classe aura un accès complet à HttpRequest et donc à tous les paramètres supplémentaires que vous soumettez. Si votre objectif est d'utiliser d'une manière ou d'une autre ces valeurs pour modifier le nom d'utilisateur et le mot de passe, vous devez le faire ici.

Autres conseils

Toutes les solutions ci-dessus sont excellentes et parfaites. Mais j'ai utilisé un type de solution de contournement qui fonctionne parfaitement. Identifiant multi-locataires utilisé pour 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 {

    }
}

XML de sécurité de printemps     

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

Objet de demande d'accès dans votre classe d'authentification

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

Utilisez ensuite l'objet de requête pour obtenir vos paramètres personnalisés

Le truc, c’est que vous devez créer un nouveau AuthenicationToken (peut-être) étendant UsernameAndPasswordAuthenicationToken et comme @emills indique que vous devez ensuite implémenter un nouveau AuthenciationProcessingFilter pour mapper les valeurs de demande au jeton et les soumettre à AuthenicationManager.

En principe, la mise en œuvre d’une chaîne d’authentification personnalisée dans Spring-security se compose de plusieurs éléments

.
  • AuthenicationToken - détails de la demande d'authentification et de son résultat, c'est-à-dire contient les informations d'identification dont vous avez besoin pour vous authentifier
  • AuthenicationProvider - enregistré auprès de AuthenicationManager, accepte votre AuthenicationToken, valide l'utilisateur et renvoie un jeton avec le jeu d'autorisations accordées
  • AuthenciationFilter - il n'est pas nécessaire que ce soit un filtre: utiliser simplement AbstractProcessingFilter vous facilitera la vie

Je voudrais aller de cette façon:

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

C'est la classe qui contient les propriétés:

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

Vous avez maintenant le nom d'utilisateur, le mot de passe et les détails.

J'ai fait la même chose, mais différent de ce que quiconque a suggéré ici. Je ne dis pas que c’est le "droit" façon de le faire - mais cela a très bien fonctionné pour moi. Dans l'objet Principal, il y a l'utilisateur et il y a aussi un objet Détails dans AuthenticationToken qui permet de stocker une carte (String, String) contenant d'autres informations de connexion.

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

Maintenant, n’importe où dans votre code, utilisez SecurityContext pour propager ces informations relatives à la sécurité sans avoir à les coupler à votre objet UserDetails, ni à les transmettre en tant qu’arguments. Je fais ce code dans un SecurityFilter à la fin de la chaîne Spring Security Filter.

<bean id="requestFormFilter" class="...RequestFormDetails">
   <custom-filter position="LAST" />
</bean> 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top