Pregunta

La intención aquí es lidiar con contraseñas confusas para recursos.

Tenemos un asesor que intercepta las llamadas a setPassword y descifra el argumento.

Hemos creado una plantilla que se parece a esto:

<bean id="pwAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
   <property name="advice"><bean class="our.advice.bean.class"/></property>
   <property name="mappedName" value="setPassword"/>
</bean>
<bean id="passwordHandlerTemplate" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true">
   <property name="interceptorNames"><list><value>pwAdvisor</value></list></property>
</bean>

No tengo claro la sintaxis exacta para usarlo. La forma más obvia es:

<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
   <property name="target">
      <bean class="the.target.class.name">
         <property name="password" value="encrypted garbage"/>
      </bean>
    </property>
 </bean>

Pero eso no funciona bien, ya que la propiedad de la contraseña se aplica al bean interno, lo que significa que el asesor no terminará haciendo su trabajo.

Bueno, ¿qué pasa con esto?

<bean id="myPasswordProtectedThing" parent="passwordHandlerTemplate">
   <property name="target"><bean class="the.target.class.name"/></property>
   <property name="password" value="encrypted garbage"/>
</bean>

No. Spring se queja de que el ProxyFactoryBean no tiene una propiedad de contraseña. Y, por supuesto, no es así. Lo que tiene la propiedad de contraseña es lo que el bean de fábrica crea .

Bueller?

¿Fue útil?

Solución

Mi primer esfuerzo fue pobre, pero tenía prisa. Me disculpo. Ahora creo que sé cómo debería funcionar, porque creo que he implementado lo que quiero para mí.

Comencé con una clase de credencial (nota: sin interfaz):


package aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Credential
{
   private static final String DEFAULT_USERNAME = "username";
   private static final String DEFAULT_PASSWORD = "password";

   private String username;
   private String password;

   public static void main(String[] args)
   {
      Credential cred1 = new Credential("foo", "bar");
      System.out.println("created using new: " + cred1);

      ApplicationContext context = new ClassPathXmlApplicationContext("classpath:aop-context.xml");
      Credential cred2 = (Credential) context.getBean("credential");

      System.out.println("created using app context: " + cred2);

      String password = ((args.length > 0) ? args[0] : "baz");
      cred2.setPassword(password);

      System.out.println("initialized using setter: " + cred2);      
   }

   public Credential()
   {
      this(DEFAULT_USERNAME, DEFAULT_PASSWORD);
   }

   public Credential(String username, String password)
   {
      this.setUsername(username);
      this.setPassword(password);
   }

   public String getUsername()
   {
      return username;
   }

   public void setUsername(String username)
   {
      this.username = username;
   }

   public String getPassword()
   {
      return password;
   }

   public void setPassword(String password)
   {
      this.password = password;
   }


   public String toString()
   {
      return new StringBuilder().append("Credential{").append("username='").append(username).append('\'').append(", password='").append(password).append('\'').append('}').toString();
   }
}

Creé una interfaz de Decryptor:


package aop;

public interface Decryptor
{
   String decrypt(String encrypted);
}

Y un DecryptorImpl:


package aop;

public class DecryptorImpl implements Decryptor
{
   public static final String DEFAULT_DECRYPTED_VALUE = " - not secret anymore";

   public String decrypt(String encrypted)
   {
      // Any transform will do; this suffices to demonstrate
      return encrypted + DEFAULT_DECRYPTED_VALUE;
   }
}


Necesitaba DecryptorAdvice para implementar el MethodBeforeAdvice de Spring:



package aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class DecryptionAdvice implements MethodBeforeAdvice
{
   private Decryptor decryptor;


   public DecryptionAdvice(Decryptor decryptor)
   {
      this.decryptor = decryptor;
   }

   public void before(Method method, Object[] args, Object target) throws Throwable
   {
      String encryptedPassword = (String) args[0];

      args[0] = this.decryptor.decrypt(encryptedPassword);
   }
}

Y lo conecté en un aop-context.xml. (Si me dice cómo hacer que se muestre XML, lo publicaré). Tenga en cuenta el passwordDecryptionAdvisor: solo coincide con el método setPassword.

La parte interesante pasa cuando lo ejecuto. Esto es lo que veo en la consola:


created using new: Credential{username='foo', password='bar'}
created using app context: Credential{username='stackoverflow', password='encrypted-password'}
initialized using setter: Credential{username='stackoverflow', password='baz - not secret anymore'}

Lo que esto me dice es:

  1. Si creo un objeto con nuevo es no bajo el control de primavera, consejo no se aplica.
  2. Si llamo a setPassword en el ctor antes de que el contexto de la aplicación sea inicializado, el consejo no se aplica.
  3. Si llamo a setPassword en mi código después de que el contexto de la aplicación es Inicializado, se aplica el consejo.

Espero que esto pueda ayudarte.

Otros consejos

Pensé que querías que el consejo de Método anterior utilizara la cadena de contraseña cifrada que se pasa al método setPassword. Desea descifrar eso y hacer que la clase aconsejada obtenga una versión descifrada.

Tampoco veo una interfaz de proxy configurada en su fábrica de proxy. " Primavera en acción " dice " ... Se favorece la creación de un proxy con interfaces sobre las clases de proxy ... " Las clases de proxy deben ser la excepción, no la regla.

Publica tu clase de consejos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top