Se voce está utilizando as funcionalidades de autenticação do ASP.NET 2.0, então é provável que voce já se deparou com a necessidade de recuperar/redefinir (PasswordRecovery) a senha de uma determinado usuário. Há um detalhe importante a ser observado quando voce habilita esta funcionalidade.
O comportamento deste controle merece uma atenção especial para os dois cenários suportados:
-
enablePasswordRetrieval = true: quando esta opção está definida como true, obriga voce também a definir a propriedade passwordFormat para um valor diferente de Hashed. Se esta combinação de valores for atendida, a senha será recuperada da base de dados e enviada para o e-mail do respectivo usuário.
-
enablePasswordRetrieval = false: esta configuração é geralmente utilizada quando a propriedade passwordFormat é definida como Hashed, ou seja, não será possível recuperar a senha da base de dados, pois ela foi hasheada. Neste caso, quando o usuário utilizar o controle PasswordRecovery, então ele gerará uma nova senha e, é neste momento que começa toda a confusão.
O processo para a geração da nova senha invoca, indiretamente, o método GeneratePassword do provider selecionado que, na maioria dos casos, é o SqlMembershipProvider. Dentro deste método há uma chamada para o método estático GeneratePassword da classe Membership. A confusão ocorre aqui por causa de dois atributos que são configurados no arquivo Web.Config: minRequiredPasswordLength e minRequiredNonalphanumericCharacters. Esses valores servem apenas para validação de senhas informadas pelo usuário mas, para o processo de geração automática (reset), são desprezados.
O SqlMembershipProvider tem um comportamento padrão que é: se o valor informado no atributo minRequiredPasswordLength for menor que 14, ele assume 14; o valor do atributo minRequiredNonalphanumericCharacters é sempre informado mas, pela lógica implementada, não mudará em nada.
O que voce precisa fazer é sobrescrever o método GeneratePassword da classe SqlMembershipProvider e, colocar a regra necessária para mudar o comportamento padrão. Eis aqui uma possível implementação:
using System.Security.Cryptography;
public class CustomMembershipProvider : SqlMembershipProvider
{
private static char[] chars = “a0bc1d2efgh3i4jkl5m6n7o8p9qrstuvuyzw”.ToCharArray();
public override string GeneratePassword()
{
if (this.MinRequiredNonAlphanumericCharacters == 0)
{
byte[] randomBytes = new byte[this.MinRequiredPasswordLength];
char[] result = new char[this.MinRequiredPasswordLength];
new RNGCryptoServiceProvider().GetBytes(randomBytes);
for (int i = 0; i < this.MinRequiredPasswordLength; i++)
{
int index = ((int)randomBytes[i]) % chars.Length;
result[i] = chars[index];
}
return new string(result);
}
else
{
return base.GeneratePassword();
}
}
}
//Configuração (Web.Config):
<membership defaultProvider=”SqlMembershipProvider”>
<providers>
<clear/>
<add
name=”SqlMembershipProvider”
type=”CustomMembershipProvider”
minRequiredNonalphanumericCharacters=”0″
minRequiredPasswordLength=”5″/>
</providers>
</membership>