Validar credenciais de usuário no repositório de usuário associado (C#)
por Scott Mitchell
Observação
Desde que este artigo foi escrito, os provedores de associação ASP.NET foram substituídos pelo ASP.NET Identity. É altamente recomendável atualizar aplicativos para usar a plataforma ASP.NET Identity em vez dos provedores de associação apresentados no momento em que este artigo foi escrito. ASP.NET Identity tem várias vantagens em relação ao sistema de associação ASP.NET, incluindo :
- Melhor desempenho
- Extensibilidade e testabilidade aprimoradas
- Suporte para OAuth, OpenID Connect e autenticação de dois fatores
- Suporte à identidade baseada em declarações
- Melhor interoperabilidade com o ASP.Net Core
Neste tutorial, examinaremos como validar as credenciais de um usuário no repositório de usuários associados usando os meios programáticos e o controle logon. Também veremos como personalizar a aparência e o comportamento do controle de logon.
Introdução
No tutorial anterior, analisamos como criar uma nova conta de usuário na estrutura Associação. Primeiro examinamos a criação programática de contas de usuário por meio do Membership
método da CreateUser
classe e, em seguida, examinamos usando o controle Web CreateUserWizard. No entanto, a página de logon valida atualmente as credenciais fornecidas em relação a uma lista embutida em código de pares de nome de usuário e senha. Precisamos atualizar a lógica da página de logon para que ela valide as credenciais no repositório de usuários da estrutura de associação.
Assim como ocorre com a criação de contas de usuário, as credenciais podem ser validadas programaticamente ou declarativamente. A API de Associação inclui um método para validar programaticamente as credenciais de um usuário no repositório de usuários. E ASP.NET é fornecido com o controle Da Web de Logon, que renderiza uma interface do usuário com caixas de texto para o nome de usuário e senha e um botão para fazer logon.
Neste tutorial, examinaremos como validar as credenciais de um usuário no repositório de usuários associados usando os meios programáticos e o controle logon. Também veremos como personalizar a aparência e o comportamento do controle de logon. Vamos começar!
Etapa 1: Validando credenciais no repositório de usuários associados
Para sites que usam autenticação de formulários, um usuário faz logon no site visitando uma página de logon e inserindo suas credenciais. Essas credenciais são comparadas com o repositório de usuários. Se forem válidos, o usuário receberá um tíquete de autenticação de formulários, que é um token de segurança que indica a identidade e a autenticidade do visitante.
Para validar um usuário em relação à estrutura Associação, use o Membership
método da ValidateUser
classe . O ValidateUser
método usa dois parâmetros de entrada - username
e password
- e retorna um valor booliano que indica se as credenciais eram válidas. Assim como acontece com o CreateUser
método que examinamos no tutorial anterior, o ValidateUser
método delega a validação real para o provedor de associação configurado.
O SqlMembershipProvider
valida as credenciais fornecidas obtendo a senha do usuário especificado por meio do aspnet_Membership_GetPasswordWithFormat
procedimento armazenado. Lembre-se de que o armazena as SqlMembershipProvider
senhas dos usuários usando um dos três formatos: clear, encrypted ou hash. O aspnet_Membership_GetPasswordWithFormat
procedimento armazenado retorna a senha em seu formato bruto. Para senhas criptografadas ou com hash, o SqlMembershipProvider
transforma o password
valor passado para o ValidateUser
método em seu estado criptografado ou hash equivalente e o compara com o que foi retornado do banco de dados. Se a senha armazenada no banco de dados corresponder à senha formatada inserida pelo usuário, as credenciais serão válidas.
Vamos atualizar nossa página de logon (~/Login.aspx
) para que ela valide as credenciais fornecidas no repositório de usuários da estrutura de associação. Criamos essa página de logon novamente no tutorial Uma Visão geral da Autenticação de Formulários, criando uma interface com duas TextBoxes para o nome de usuário e senha, uma caixa de seleção Lembrar-me e um botão Logon (consulte a Figura 1). O código valida as credenciais inseridas em uma lista embutida em código de pares de nome de usuário e senha (Scott/password, Jisun/password e Sam/password).
Figura 1: a interface da página de logon inclui duas TextBoxes, uma CheckBoxList e um botão (clique para exibir a imagem em tamanho real)
A interface do usuário da página de logon pode permanecer inalterada, mas precisamos substituir o manipulador de eventos do botão Logon pelo código que valida o usuário no repositório de usuários da Click
estrutura de associação. Atualize o manipulador de eventos para que seu código apareça da seguinte maneira:
protected void LoginButton_Click(object sender, EventArgs e)
{
// Validate the user against the Membership framework user store
if (Membership.ValidateUser(UserName.Text, Password.Text))
{
// Log the user into the site
FormsAuthentication.RedirectFromLoginPage(UserName.Text, RememberMe.Checked);
}
// If we reach here, the user's credentials were invalid
InvalidCredentialsMessage.Visible = true;
}
Esse código é notavelmente simples. Começamos chamando o Membership.ValidateUser
método , passando o nome de usuário e a senha fornecidos. Se esse método retornar true, o usuário será conectado ao site por meio FormsAuthentication
do método RedirectFromLoginPage da classe. (Como discutimos no Um tutorial de Visão geral da Autenticação de Formulários , o FormsAuthentication.RedirectFromLoginPage
cria o tíquete de autenticação de formulários e redireciona o usuário para a página apropriada.) No entanto, se as credenciais forem inválidas, o InvalidCredentialsMessage
Rótulo será exibido, informando ao usuário que seu nome de usuário ou senha estava incorreto.
Isso é tudo!
Para testar se a página de logon funciona conforme o esperado, tente fazer logon com uma das contas de usuário que você criou no tutorial anterior. Ou, se você ainda não criou uma conta, vá em frente e crie uma a partir da ~/Membership/CreatingUserAccounts.aspx
página.
Observação
Quando o usuário insere suas credenciais e envia o formulário de página de logon, as credenciais, incluindo sua senha, são transmitidas pela Internet para o servidor Web em texto sem formatação. Isso significa que qualquer hacker que detecte o tráfego de rede pode ver o nome de usuário e a senha. Para evitar isso, é essencial criptografar o tráfego de rede usando SSL (Secure Socket Layers). Isso garantirá que as credenciais (bem como a marcação HTML de toda a página) sejam criptografadas a partir do momento em que saírem do navegador até serem recebidas pelo servidor Web.
Como a Estrutura de Associação lida com tentativas de logon inválidas
Quando um visitante chega à página de logon e envia suas credenciais, o navegador faz uma solicitação HTTP para a página de logon. Se as credenciais forem válidas, a resposta HTTP incluirá o tíquete de autenticação em um cookie. Portanto, um hacker tentando invadir seu site pode criar um programa que envia exaustivamente solicitações HTTP para a página de logon com um nome de usuário válido e um palpite na senha. Se a suposição de senha estiver correta, a página de logon retornará o cookie de tíquete de autenticação, momento em que o programa saberá que encontrou um par de nome de usuário/senha válido. Por meio de força bruta, esse programa pode ser capaz de encontrar a senha de um usuário, especialmente se a senha for fraca.
Para evitar esses ataques de força bruta, a estrutura associação bloqueará um usuário se houver um determinado número de tentativas de logon malsucedidas dentro de um determinado período de tempo. Os parâmetros exatos são configuráveis por meio das duas definições de configuração do provedor de associação a seguir:
maxInvalidPasswordAttempts
– especifica quantas tentativas de senha inválidas são permitidas para o usuário dentro do período de tempo antes que a conta seja bloqueada. O valor padrão é 5.passwordAttemptWindow
– indica o período de tempo em minutos durante o qual o número especificado de tentativas de logon inválidas fará com que a conta seja bloqueada. O valor padrão é 10.
Se um usuário tiver sido bloqueado, ela não poderá fazer logon até que um administrador desbloqueie sua conta. Quando um usuário é bloqueado, o ValidateUser
método sempre retornará false
, mesmo se as credenciais válidas forem fornecidas. Embora esse comportamento dima a probabilidade de um hacker invadir seu site por meio de métodos de força bruta, ele pode acabar bloqueando um usuário válido que simplesmente esqueceu sua senha ou acidentalmente tem o Caps Lock ativado ou está tendo um dia de digitação ruim.
Infelizmente, não há nenhuma ferramenta interna para desbloquear uma conta de usuário. Para desbloquear uma conta, você pode modificar o banco de dados diretamente - alterar o IsLockedOut
campo na aspnet_Membership
tabela da conta de usuário apropriada - ou criar uma interface baseada na Web que lista contas bloqueadas com opções para desbloqueá-las. Examinaremos a criação de interfaces administrativas para realizar tarefas comuns relacionadas à conta de usuário e à função em um tutorial futuro.
Observação
Uma desvantagem do ValidateUser
método é que, quando as credenciais fornecidas são inválidas, ele não fornece nenhuma explicação sobre o motivo. As credenciais podem ser inválidas porque não há nenhum par de nome de usuário/senha correspondente no repositório de usuários ou porque o usuário ainda não foi aprovado ou porque o usuário foi bloqueado. Na Etapa 4, veremos como mostrar uma mensagem mais detalhada ao usuário quando a tentativa de logon falhar.
Etapa 2: coletando credenciais por meio do controle da Web de logon
O controle Da Web de Logon renderiza uma interface do usuário padrão muito semelhante à que criamos no tutorial Uma Visão geral da Autenticação de Formulários. Usar o controle logon nos salva o trabalho de ter que criar a interface para coletar as credenciais do visitante. Além disso, o controle Logon entra automaticamente no usuário (supondo que as credenciais enviadas sejam válidas), evitando assim que seja preciso escrever qualquer código.
Vamos atualizar Login.aspx
, substituindo a interface e o código criados manualmente por um controle login. Comece removendo a marcação e o código existentes no Login.aspx
. Você pode excluí-lo imediatamente ou simplesmente comente-o. Para comentar a marcação declarativa, coloque-a entre os <%--
delimitadores e --%>
. Você pode inserir esses delimitadores manualmente ou, como mostra a Figura 2, pode selecionar o texto para comentar e clicar no ícone Comentar as linhas selecionadas na Barra de Ferramentas. Da mesma forma, você pode usar o ícone Comentar as linhas selecionadas para comentar o código selecionado na classe code-behind.
Figura 2: Comentar a Marcação Declarativa Existente e o Código-Fonte em Login.aspx
(Clique para exibir a imagem em tamanho real)
Observação
O ícone Comentar as linhas selecionadas não está disponível ao exibir a marcação declarativa no Visual Studio 2005. Se você não estiver usando o Visual Studio 2008, precisará adicionar manualmente os <%--
delimitadores e --%>
.
Em seguida, arraste um controle Login da Caixa de Ferramentas para a página e defina sua propriedade como ID
myLogin
. Neste ponto, sua tela deve ser semelhante à Figura 3. Observe que a interface padrão do controle de logon inclui controles TextBox para o nome de usuário e senha, um CheckBox da próxima vez em Remember me e um Botão de Logon. Também há RequiredFieldValidator
controles para as duas TextBoxes.
Figura 3: Adicionar um controle de logon à página (clique para exibir a imagem em tamanho real)
E nós terminamos! Quando o botão Fazer Logon do controle de logon for clicado, ocorrerá um postback e o controle de logon chamará o Membership.ValidateUser
método , passando o nome de usuário e a senha inseridos. Se as credenciais forem inválidas, o controle Logon exibirá uma mensagem informando isso. Se, no entanto, as credenciais forem válidas, o controle Logon criará o tíquete de autenticação de formulários e redirecionará o usuário para a página apropriada.
O controle Logon usa quatro fatores para determinar a página apropriada para redirecionar o usuário após um logon bem-sucedido:
- Se o controle logon está na página de logon, conforme definido pela
loginUrl
configuração na configuração de autenticação de formulários; o valor padrão dessa configuração éLogin.aspx
- A presença de um
ReturnUrl
parâmetro querystring - O valor da propriedade do
DestinationUrl
controle login - O
defaultUrl
valor especificado nas definições de configuração de autenticação de formulários; o valor padrão dessa configuração éDefault.aspx
A Figura 4 descreve como o controle Login usa esses quatro parâmetros para chegar à sua decisão de página apropriada.
Figura 4: Adicionar um controle de logon à página (clique para exibir a imagem em tamanho real)
Reserve um momento para testar o controle de logon visitando o site por meio de um navegador e fazendo logon como um usuário existente na estrutura Associação.
A interface renderizada do controle de logon é altamente configurável. Há várias propriedades que influenciam sua aparência; além disso, o controle Login pode ser convertido em um modelo para controle preciso sobre o layout dos elementos da interface do usuário. O restante desta etapa examina como personalizar a aparência e o layout.
Personalizando a aparência do controle de logon
As configurações de propriedade padrão do controle de logon renderizam uma interface do usuário com um título ( Logon ), controles TextBox e Label para as entradas de nome de usuário e senha, uma CheckBox da próxima vez e um botão Fazer Logon. As aparências desses elementos são configuráveis por meio das inúmeras propriedades do controle login. Além disso, elementos adicionais da interface do usuário - como um link para uma página para criar uma nova conta de usuário - podem ser adicionados definindo uma propriedade ou duas.
Vamos passar alguns instantes para gussy até a aparência do nosso controle login. Como a Login.aspx
página já tem texto na parte superior da página que diz Logon, o título do controle de logon é supérfluo. Portanto, limpe o valor da TitleText
propriedade para remover o título do controle de logon.
Os rótulos Nome de Usuário: e Senha: à esquerda dos dois controles TextBox podem ser personalizados por meio das UserNameLabelText
propriedades e PasswordLabelText
, respectivamente. Vamos alterar o Nome de Usuário: Rótulo para ler Nome de usuário:. Os estilos Label e TextBox são configuráveis por meio das LabelStyle
propriedades e TextBoxStyle
, respectivamente.
A propriedade Lembrar-me da próxima vez que a propriedade Texto da CheckBox puder ser definida por meio do RememberMeText property
do controle de logon e seu estado de verificação padrão for configurável por meio do RememberMeSet property
(que usa como padrão False). Vá em frente e defina a RememberMeSet
propriedade como True para que a caixa de seleção Lembrar-me da próxima vez seja verificada por padrão.
O controle Login oferece duas propriedades para ajustar o layout de seus controles de interface do usuário. O TextLayout property
indica se os rótulos Nome de usuário: e Senha: aparecem à esquerda de suas TextBoxes correspondentes (o padrão) ou acima delas. O Orientation property
indica se as entradas de nome de usuário e senha estão situadas verticalmente (uma acima da outra) ou horizontalmente. Vou deixar essas duas propriedades definidas como seus padrões, mas encorajo você a tentar definir essas duas propriedades com seus valores não padrão para ver o efeito resultante.
Observação
Na próxima seção, Configurando o Layout do Controle de Logon, examinaremos o uso de modelos para definir o layout preciso dos elementos da interface do usuário do controle layout.
Encapsular as configurações de propriedade do controle de logon definindo as CreateUserText
propriedades e CreateUserUrl
como Não registrados ainda? Crie uma conta! e ~/Membership/CreatingUserAccounts.aspx
, respectivamente. Isso adiciona um hiperlink à interface do controle de logon apontando para a página que criamos no tutorial anterior. As propriedades e propriedades e PasswordRecoveryUrl
HelpPageUrl
PasswordRecoveryText
do controle de HelpPageText
logon funcionam da mesma maneira, renderizando links para uma página de ajuda e uma página de recuperação de senha.
Depois de fazer essas alterações de propriedade, a marcação declarativa e a aparência do controle de logon devem ser semelhantes às mostradas na Figura 5.
Figura 5: Os valores das propriedades do controle de logon ditam sua aparência (clique para exibir a imagem em tamanho real)
Configurando o layout do controle de logon
A interface do usuário padrão do controle da Web de logon estabelece a interface em um HTML <table>
. Mas e se precisarmos de um controle mais fino sobre a saída renderizada? Talvez queiramos substituir o <table>
por uma série de <div>
marcas. Ou e se nosso aplicativo exigir credenciais adicionais para autenticação? Muitos sites financeiros, por exemplo, exigem que os usuários forneçam não apenas um nome de usuário e senha, mas também um PIN (Número de Identificação Pessoal) ou outras informações de identificação. Quaisquer que sejam os motivos, é possível converter o controle login em um modelo, do qual podemos definir explicitamente a marcação declarativa da interface.
Precisamos fazer duas coisas para atualizar o controle de logon para coletar credenciais adicionais:
- Atualize a interface do controle de logon para incluir controles da Web para coletar as credenciais adicionais.
- Substitua a lógica de autenticação interna do controle de logon para que um usuário só seja autenticado se seu nome de usuário e senha forem válidos e suas credenciais adicionais também forem válidas.
Para realizar a primeira tarefa, precisamos converter o controle de Logon em um modelo e adicionar os controles da Web necessários. Quanto à segunda tarefa, a lógica de autenticação do controle de logon pode ser substituída criando um manipulador de eventos para o evento do Authenticate
controle.
Vamos atualizar o controle de Logon para que ele solicite aos usuários o nome de usuário, a senha e o endereço de email e autentique o usuário somente se o endereço de email fornecido corresponder ao endereço de email no arquivo. Primeiro, precisamos converter a interface do controle de logon em um modelo. Na Marca Inteligente do controle de logon, escolha a opção Converter em modelo.
Figura 6: Converter o controle de logon em um modelo (clique para exibir a imagem em tamanho real)
Observação
Para reverter o controle Logon à sua versão de pré-modelo, clique no link Redefinir da Marca Inteligente do controle.
Converter o controle Login em um modelo adiciona um LayoutTemplate
à marcação declarativa do controle com elementos HTML e controles Da Web que definem a interface do usuário. Como mostra a Figura 7, converter o controle em um modelo remove várias propriedades do janela Propriedades, como TitleText
, CreateUserUrl
e assim por diante, uma vez que esses valores de propriedade são ignorados ao usar um modelo.
Figura 7: Menos propriedades estão disponíveis quando o controle de logon é convertido em um modelo (clique para exibir a imagem em tamanho real)
A marcação HTML no LayoutTemplate
pode ser modificada conforme necessário. Da mesma forma, fique à vontade para adicionar novos controles Da Web ao modelo. No entanto, é importante que os principais controles Da Web do controle de logon permaneçam no modelo e mantenham seus valores atribuídos ID
. Em particular, não remova nem renomeie as UserName
Caixas de Texto ou Password
, a RememberMe
Caixa de Seleção, o LoginButton
Botão, o FailureText
Rótulo ou os RequiredFieldValidator
controles.
Para coletar o endereço de email do visitante, precisamos adicionar uma TextBox ao modelo. Adicione a seguinte marcação declarativa entre a linha da tabela (<tr>
) que contém a Password
TextBox e a linha da tabela que contém a Caixa de Seleção Lembrar-me da próxima vez:
<tr>
<td align="right">
<asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">Email:</asp:Label>
</td>
<td>
<asp:TextBox ID="Email" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="EmailRequired" runat="server"
ControlToValidate="Email" ErrorMessage="Email is required."
ToolTip="Email is required." ValidationGroup="myLogin">*</asp:RequiredFieldValidator>
</td>
</tr>
Depois de adicionar o Email
TextBox, visite a página por meio de um navegador. Como mostra a Figura 8, a interface do usuário do controle de logon agora inclui uma terceira caixa de texto.
Figura 8: O controle de logon agora inclui uma caixa de texto para o endereço de Email do usuário (clique para exibir a imagem em tamanho real)
Neste ponto, o controle Login ainda está usando o Membership.ValidateUser
método para validar as credenciais fornecidas. Correspondentemente, o valor inserido no Email
TextBox não tem nenhuma influência sobre se o usuário pode fazer logon. Na Etapa 3, examinaremos como substituir a lógica de autenticação do controle de logon para que as credenciais sejam consideradas válidas somente se o nome de usuário e a senha forem válidos e o endereço de email fornecido corresponder ao endereço de email no arquivo.
Etapa 3: Modificando a lógica de autenticação do controle de logon
Quando um visitante fornece suas credenciais e clica no botão Fazer Logon, um postback se segue e o controle logon progride por meio de seu fluxo de trabalho de autenticação. O fluxo de trabalho começa acionando o LoggingIn
evento. Todos os manipuladores de eventos associados a esse evento podem cancelar a operação de logon definindo a e.Cancel
propriedade true
como .
Se a operação de logon não for cancelada, o fluxo de trabalho progride gerando o Authenticate
evento. Se houver um manipulador de eventos para o Authenticate
evento, ele será responsável por determinar se as credenciais fornecidas são válidas ou não. Se nenhum manipulador de eventos for especificado, o controle Login usará o Membership.ValidateUser
método para determinar a validade das credenciais.
Se as credenciais fornecidas forem válidas, o tíquete de autenticação de formulários será criado, o LoggedIn
evento será gerado e o usuário será redirecionado para a página apropriada. Se, no entanto, as credenciais forem consideradas inválidas, o LoginError
evento será gerado e uma mensagem será exibida informando ao usuário que suas credenciais eram inválidas. Por padrão, em caso de falha, o controle Logon simplesmente define FailureText
a propriedade Text do controle Label como uma mensagem de falha ( Sua tentativa de logon não foi bem-sucedida. Tente novamente ). No entanto, se a propriedade do FailureAction
controle Login estiver definida RedirectToLoginPage
como , o controle Logon emitirá um Response.Redirect
para a página de logon acrescentando o parâmetro loginfailure=1
querystring (o que faz com que o controle login exiba a mensagem de falha).
A Figura 9 oferece um fluxograma do fluxo de trabalho de autenticação.
Figura 9: O fluxo de trabalho de autenticação do controle de logon (clique para exibir a imagem em tamanho real)
Observação
Se você estiver se perguntando quando usaria a opção FailureAction
de página , RedirectToLogin
considere o cenário a seguir. No momento, nossa Site.master
página master tem o texto Olá, estranho exibido na coluna esquerda quando visitado por um usuário anônimo, mas imagine que queríamos substituir esse texto por um controle de Logon. Isso permitiria que um usuário anônimo faça logon de qualquer página no site, em vez de exigir que ele visite a página de logon diretamente. No entanto, se um usuário não conseguir fazer logon por meio do controle de logon renderizado pela página master, talvez faça sentido redirecioná-lo para a página de logon (Login.aspx
) porque essa página provavelmente inclui instruções adicionais, links e outras ajudas, como links para criar uma nova conta ou recuperar uma senha perdida, que não foram adicionadas à página master.
Criando oAuthenticate
manipulador de eventos
Para conectar nossa lógica de autenticação personalizada, precisamos criar um manipulador de eventos para o evento do controle de Authenticate
logon. A criação de um manipulador de eventos para o Authenticate
evento gerará a seguinte definição de manipulador de eventos:
protected void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
}
Como você pode ver, o Authenticate
manipulador de eventos recebe um objeto do tipo AuthenticateEventArgs
como seu segundo parâmetro de entrada. A AuthenticateEventArgs
classe contém uma propriedade booliana chamada Authenticated
que é usada para especificar se as credenciais fornecidas são válidas. Nossa tarefa, então, é escrever um código aqui que determine se as credenciais fornecidas são válidas ou não e definir a e.Authenticate
propriedade adequadamente.
Determinando e validando as credenciais fornecidas
Use as propriedades e Password
do controle de UserName
logon para determinar as credenciais de nome de usuário e senha inseridas pelo usuário. Para determinar os valores inseridos em quaisquer controles Web adicionais (como o Email
TextBox que adicionamos na etapa anterior), use.FindControl
LoginControlID
("controlID
") para obter uma referência programática ao controle Web no modelo cuja ID
propriedade é igual a controlID
. Por exemplo, para obter uma referência ao Email
TextBox, use o seguinte código:
TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;
Para validar as credenciais do usuário, precisamos fazer duas coisas:
- Verifique se o nome de usuário e a senha fornecidos são válidos
- Verifique se o endereço de email inserido corresponde ao endereço de email no arquivo para o usuário que está tentando fazer logon
Para realizar o primeiro marcar podemos simplesmente usar o Membership.ValidateUser
método como vimos na Etapa 1. Para o segundo marcar, precisamos determinar o endereço de email do usuário para que possamos compará-lo com o endereço de email inserido no controle TextBox. Para obter informações sobre um usuário específico, use o Membership
método da GetUser
classe .
O GetUser
método tem várias sobrecargas. Se usado sem passar parâmetros, ele retornará informações sobre o usuário conectado no momento. Para obter informações sobre um usuário específico, chame GetUser
passando seu nome de usuário. De qualquer forma, GetUser
retorna um MembershipUser
objeto, que tem propriedades como UserName
, Email
, IsApproved
, IsOnline
e assim por diante.
O código a seguir implementa essas duas verificações. Se ambos passarem, será e.Authenticate
definido como true
, caso contrário, ele será atribuído false
a .
protected void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
// Get the email address entered
TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;
string email = EmailTextBox.Text.Trim();
// Verify that the username/password pair is valid
if (Membership.ValidateUser(myLogin.UserName, myLogin.Password))
{
// Username/password are valid, check email
MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
if (usrInfo != null && string.Compare(usrInfo.Email, email, true) == 0)
{
// Email matches, the credentials are valid
e.Authenticated = true;
}
else
{
// Email address is invalid...
e.Authenticated = false;
}
}
else
{
// Username/password are not valid...
e.Authenticated = false;
}
}
Com esse código em vigor, tente fazer logon como um usuário válido, inserindo o nome de usuário, a senha e o endereço de email corretos. Tente novamente, mas desta vez use propositalmente um endereço de email incorreto (consulte a Figura 10). Por fim, tente uma terceira vez usando um nome de usuário inexistente. No primeiro caso, você deve estar conectado com êxito ao site, mas nos dois últimos casos você deverá ver a mensagem de credenciais inválidas do controle de logon.
Figura 10: O Tito não pode fazer logon ao fornecer um endereço de Email incorreto (clique para exibir a imagem em tamanho real)
Observação
Conforme discutido na seção How the Membership Framework Handles Invalid Login Attempts in Invalid Login Attempts in Step 1, when the Membership.ValidateUser
method is called and passed invalid credentials, it keeps track of the invalid login attempt and locks out the user if they exceed a certain threshold of invalid attempts within a specified time window. Como nossa lógica de autenticação personalizada chama o ValidateUser
método , uma senha incorreta para um nome de usuário válido incrementará o contador de tentativa de logon inválido, mas esse contador não é incrementado no caso em que o nome de usuário e a senha são válidos, mas o endereço de email está incorreto. As chances são de que esse comportamento seja adequado, pois é improvável que um hacker conheça o nome de usuário e a senha, mas tenha que usar técnicas de força bruta para determinar o endereço de email do usuário.
Etapa 4: Aprimorando a mensagem de credenciais inválidas do controle de logon
Quando um usuário tenta fazer logon com credenciais inválidas, o controle Logon exibe uma mensagem explicando que a tentativa de logon não foi bem-sucedida. Em particular, o controle exibe a mensagem especificada por sua FailureText
propriedade, que tem um valor padrão de Sua tentativa de logon não foi bem-sucedida. Tente novamente.
Lembre-se de que há muitos motivos pelos quais as credenciais de um usuário podem ser inválidas:
- O nome de usuário pode não existir
- O nome de usuário existe, mas a senha é inválida
- O nome de usuário e a senha são válidos, mas o usuário ainda não foi aprovado
- O nome de usuário e a senha são válidos, mas o usuário está bloqueado (provavelmente porque excedeu o número de tentativas de logon inválidas dentro do período especificado)
E pode haver outros motivos ao usar a lógica de autenticação personalizada. Por exemplo, com o código que escrevemos na Etapa 3, o nome de usuário e a senha podem ser válidos, mas o endereço de email pode estar incorreto.
Independentemente do motivo pelo qual as credenciais são inválidas, o controle Logon exibe a mesma mensagem de erro. Essa falta de comentários pode ser confusa para um usuário cuja conta ainda não foi aprovada ou que foi bloqueada. No entanto, com um pouco de trabalho, podemos fazer com que o controle logon exiba uma mensagem mais apropriada.
Sempre que um usuário tenta fazer logon com credenciais inválidas, o controle logon gera seu LoginError
evento. Vá em frente e crie um manipulador de eventos para esse evento e adicione o seguinte código:
protected void myLogin_LoginError(object sender, EventArgs e)
{
// Determine why the user could not login...
myLogin.FailureText = "Your login attempt was not successful. Please try again.";
// Does there exist a User account for this user?
MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
if (usrInfo != null)
{
// Is this user locked out?
if (usrInfo.IsLockedOut)
{
myLogin.FailureText = "Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked.";
}
else if (!usrInfo.IsApproved)
{
myLogin.FailureText = "Your account has not yet been approved. You cannot login until an administrator has approved your account.";
}
}
}
O código acima começa definindo a propriedade do controle de FailureText
logon como o valor padrão ( Sua tentativa de logon não foi bem-sucedida. Tente novamente ). Em seguida, ele verifica se o nome de usuário fornecido é mapeado para uma conta de usuário existente. Nesse caso, ele consulta as propriedades e IsApproved
do IsLockedOut
objeto resultante MembershipUser
para determinar se a conta foi bloqueada ou ainda não foi aprovada. Em ambos os casos, a FailureText
propriedade é atualizada para um valor correspondente.
Para testar esse código, tente fazer logon propositalmente como um usuário existente, mas use uma senha incorreta. Faça isso cinco vezes seguidas em um período de 10 minutos e a conta será bloqueada. Como mostra a Figura 11, as tentativas de logon subsequentes sempre falharão (mesmo com a senha correta), mas agora exibirão o mais descritivo Sua conta foi bloqueada devido a muitas tentativas de logon inválidas. Entre em contato com o administrador para que sua conta seja desbloqueada.
Figura 11: Tito realizou muitas tentativas de logon inválidas e foi bloqueado (clique para exibir a imagem em tamanho real)
Resumo
Antes deste tutorial, nossa página de logon validava as credenciais fornecidas em uma lista codificada de pares de nome de usuário/senha. Neste tutorial, atualizamos a página para validar as credenciais na estrutura associação. Na Etapa 1, examinamos o uso do Membership.ValidateUser
método programaticamente. Na Etapa 2, substituímos nossa interface do usuário e o código criados manualmente pelo controle de logon.
O controle Logon renderiza uma interface do usuário de logon padrão e valida automaticamente as credenciais do usuário em relação à estrutura de associação. Além disso, no caso de credenciais válidas, o controle Logon assina o usuário por meio da autenticação de formulários. Em suma, uma experiência de usuário de logon totalmente funcional está disponível simplesmente arrastando o controle de logon para uma página, sem marcação declarativa extra ou código necessário. Além disso, o controle logon é altamente personalizável, permitindo um bom grau de controle sobre a interface do usuário renderizada e a lógica de autenticação.
Neste ponto, os visitantes do nosso site podem criar uma nova conta de usuário e fazer logon no site, mas ainda não analisamos restringir o acesso a páginas com base no usuário autenticado. Atualmente, qualquer usuário, autenticado ou anônimo, pode exibir qualquer página em nosso site. Além de controlar o acesso às páginas do nosso site por usuário, podemos ter determinadas páginas cuja funcionalidade depende do usuário. O próximo tutorial analisa como limitar o acesso e a funcionalidade na página com base no usuário conectado.
Programação feliz!
Leitura Adicional
Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:
- Exibindo mensagens personalizadas para usuários bloqueados e não aprovados
- Examinando a associação, as funções e o perfil do ASP.NET 2.0
- Como criar uma página de logon ASP.NET
- Documentação técnica do controle de logon
- Usando os controles de logon
Sobre o autor
Scott Mitchell, autor de vários livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Scott pode ser contatado em mitchell@4guysfromrolla.com ou através de seu blog em http://ScottOnWriting.NET.
Agradecimentos Especiais
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Teresa Murphy e Michael Olivero. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.