Domanda

L'intento qui è di gestire password offuscate per le risorse.

Abbiamo un consulente che intercetta le chiamate a setPassword e decodifica l'argomento.

Abbiamo creato un modello che assomiglia in qualche modo a questo:

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

Non sono chiaro l'esatta sintassi per usarlo. Il modo più ovvio è:

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

Ma ciò non funziona correttamente, poiché la proprietà password viene applicata al bean interno, il che significa che l'advisor non finirà per fare il suo lavoro.

Bene, che dire di questo:

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

No. Spring si lamenta che ProxyFactoryBean non ha una proprietà password. E, ovviamente, non lo fa. La cosa che ha la proprietà password è quella che il bean factory crea .

Bueller?

È stato utile?

Soluzione

Il mio primo sforzo è stato scarso, ma avevo fretta. Chiedo scusa. Ora penso di sapere come dovrebbe funzionare, perché credo di aver implementato ciò che vuoi tu stesso.

Ho iniziato con una classe di credenziali (nota: nessuna interfaccia):


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

Ho creato un'interfaccia Decryptor:


package aop;

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

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

Avevo bisogno di DecryptorAdvice per implementare il metodo SpringBeforeAdvice di 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);
   }
}

E l'ho collegato insieme in aop-context.xml. (Se mi dici come ottenere XML da visualizzare, lo pubblicherò.) Nota passwordDecryptionAdvisor: corrisponde solo al metodo setPassword.

La parte interessante accade quando la eseguo. Ecco cosa vedo nella console:


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

Ciò che mi dice è:

  1. Se creo un oggetto con nuovo è non sotto il controllo di Spring, consiglio non viene applicato.
  2. Se chiamo setPassword nel ctor prima che sia il contesto dell'app inizializzato, il consiglio non viene applicato.
  3. Se chiamo setPassword nel mio codice dopo il contesto dell'app è inizializzato, viene applicato un consiglio.

Spero che questo possa aiutarti.

Altri suggerimenti

Pensavo volessi che il consiglio beforeMethod usasse la password crittografata String che è passata nel metodo setPassword. Si desidera decrittografarlo e fare in modo che la classe consigliata ottenga una versione decrittografata.

Inoltre non vedo un'interfaccia proxy impostata nella fabbrica proxy. " Spring In Action " dice " ... La creazione di un proxy con interfacce è preferita rispetto alle classi proxy ... " Le classi proxy dovrebbero essere l'eccezione, non la regola.

Pubblica il tuo corso di consulenza.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top