ASP.NET Membership: Login e Manutenção de usuários em suas aplicações

O ASP.NET Membership é indicado pela Microsoft como a melhor ferramenta para tratar da segurança de aplicações web. Veremos nesse artigo como podemos utilizá-lo, inclusive em outros projetos .NET.

Neste artigo iremos demonstrar o uso de uma ferramenta de segurança que já vem integrada ao .NET Framework desde a versão 2.0: o Membership. É uma classe que não pode ser herdada e que é responsável por efetuar a segurança de aplicações. Ela valida as credenciais dos usuários, gerencia as configurações da aplicação, regras de acesso e muito mais. Pode ser utilizado sozinho ou em conjunto com o FormsAuthentication para efetuar a segurança de um aplicativo web ou site.

Através do provedor Membership podemos criar novos usuários e senhas em um banco de dados e validar a identidade do usuário usando a informação armazenada. Para armazenar a informação o provedor usa um banco de dados SQL Server que é gerado automaticamente, e, de forma transparente na pasta App_Data, se usarmos o modo padrão do provedor.

Podemos também utilizar a ferramenta aspnet_regsql.exe, que vem com a ASP .NET, para configurar o armazenamento de dados, ou seja adicionar a estrutura das tabelas do Membership na nossa própria base de dados.

O que o Membership fornece:

Ele depende de provedores de associação para se comunicar com a base de dados e no .NET Framework inclui uma SqlMembershipProvider que armazena informações do usuário. Após efetuar a configuração do Membership, tabelas serão criadas na sua base SQL Server a fim de gerir os dados de segurança da aplicação. Com relação às senhas, as mesmas são gravadas já criptografadas.

O Membership contém a ferramenta própria Web Site Administration (WAT), responsável para efetuar toda a administração e configuração da sua aplicação. Para acessar esta basta, após a criação do seu projeto e a configuração do Membership, acessar o no Visual Studio o menu WebSite -> ASP. NET Configuration. Lá teremos as seguintes opções:

É altamente recomendado a utilização de senhas criptografadas na configuração do provider, bastando alterar o atributo passwordFormat para Hashed ou Encrypted, onde Hashed é o formato mais seguro. Os valores da chave de criptografia dos algoritmos são armazenados no machinekey.

Antes de tudo você precisará definir algumas coisas como:

Após isso deverá configurar o membership de acordo com a sua necessidade.

Na Listagem 1 temos um exemplo de configuração que a WebConfig da nossa aplicação deverá ter após a configuração do Membership na aplicação, de acordo com a necessidade.

Listagem 1. Configuração que deverá constar no Webonfig

<configuration> <connectionStrings> <add name="MySqlConnection" connectionString="Data Source=MySqlServer;Initial Catalog=aspnetdb;Integrated Security=SSPI;" /> </connectionStrings> <system.web> <authentication mode="Forms" > <forms loginUrl="login.aspx" name=".ASPXFORMSAUTH" /> </authentication> <authorization> <deny users="?" /> </authorization> <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15"> <providers> <clear /> <add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="MySqlConnection" applicationName="MyApplication" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" requiresUniqueEmail="true" passwordFormat="Hashed" /> </providers> </membership> </system.web> </configuration>

Confira a seguir alguns métodos do Membership:

Propriedades do Membership:

NOTA: A maioria das funcionalidades que o Membership fornece são encapsuladas em vários controles Web de gerenciamento de usuário.

O Membership também fornece alguns controles que podem realizar várias funções dentro da nossa aplicação. Se vocês analisarem na paleta de componentes do Visual Studio teremos uma aba chamada Login, onde temos diversos componentes que integram diretamente com o Membership. A seguir temos um breve resumo sobre o que cada um deles é capaz de efetuar.

Esses controles funcionam em conjunto com os provedores Membership e Roles. Eles não necessitam de nenhuma linha de código para funcionarem perfeitamente, pois eles já vêm com um template definido, mas podem ser alterados bastando utilizar a opção “converter to template” e ajustar de acordo com o seu gosto.

Na Listagem 2 demonstraremos o HTML que é gerado pelo componente ChangePassword (Responsável por efetuar a alteração de senha para o usuário) e após a conversão para template. Para esse e os demais exemplos a seguir foram utilizados o Visual Studio 2010 com o .NET Framework 4.0 e a classe Membership.

Listagem 2. Código HTML ChangePassword

<asp:ChangePassword ID="ChangePassword1" runat="server" ChangePasswordFailureText="Senha(s) inválida(s)!" Width="300px"> <CancelButtonStyle /> <ChangePasswordButtonStyle /> <ChangePasswordTemplate> <table class="form-inline"> <tr> <td> <table> <tr> <td align="right"> <asp:Label ID="CurrentPasswordLabel" runat="server" AssociatedControlID="CurrentPassword">Senha:</asp:Label> </td> <td> <asp:TextBox ID="CurrentPassword" runat="server" Height="30px" MaxLength="10" required="" TextMode="Password"></asp:TextBox> <br /> </td> </tr> <tr> <td align="right"> <br /> <asp:Label ID="NewPasswordLabel" runat="server" AssociatedControlID="NewPassword">Nova Senha:</asp:Label> </td> <td> <asp:TextBox ID="NewPassword" runat="server" Height="30px" MaxLength="10" required="" TextMode="Password"></asp:TextBox> </td> </tr> <tr> <td align="right"> <br /> <asp:Label ID="ConfirmNewPasswordLabel" runat="server" AssociatedControlID="ConfirmNewPassword">Confirmação:</asp:Label> </td> <td> <asp:TextBox ID="ConfirmNewPassword" runat="server" Height="30px" MaxLength="10" required="" TextMode="Password"></asp:TextBox> </td> </tr> <tr> <td align="center" colspan="2"> <asp:CompareValidator ID="NewPasswordCompare" runat="server" ControlToCompare="NewPassword" ControlToValidate="ConfirmNewPassword" Display="Dynamic" ErrorMessage="As senhas informadas não conferem!" ValidationGroup="ChangePassword1"></asp:CompareValidator> </td> </tr> <tr> <td align="center" colspan="2" > <asp:Literal ID="FailureText" runat="server" EnableViewState="False"></asp:Literal> </td> </tr> <div class="legenda"> <tr> <td align="center" colspan="2"> <br /> </td> </tr> </div> </table> <div align="right"> <asp:Button ID="ChangePasswordPushButton" runat="server" CommandName="ChangePassword" Text="Confirmar" ValidationGroup="ChangePassword1" Width="80px" /> <asp:Button ID="btnCancelar" runat="server" formnovalidate="formnovalidate" OnClick="btnCancelar_Click" Text="Cancelar" Width="80px" /> <br /> </div> </td> </tr> </table> </ChangePasswordTemplate> <ContinueButtonStyle /> <InstructionTextStyle /> <PasswordHintStyle /> <SuccessTemplate> <table> <tr> <td> <table> <tr> <td align="center"> <h2> Alteração Senha</h2> </td> </tr> <tr> <td> <h5> Senha alterada com sucesso!</h5> </td> </tr> <tr> <td align="right"> <asp:Button ID="ContinuePushButton" runat="server" Border BorderWidth="1px" CausesValidation="False" CommandName="Continue" Text="Continuar" /> </td> </tr> </table> </td> </tr> </table> </SuccessTemplate> <TextBoxStyle /> <TitleTextStyle /> </asp:ChangePassword>

Listagem 3. PasswordRecovery código HTML

<asp:PasswordRecovery ID="PasswordRecovery1" runat="server" AnswerLabelText="Resposta:" AnswerRequiredErrorMessage="Resposta requerida." GeneralFailureText="Sua tentativa para recuperar sua senha não teve êxito. Por favor tente novamente." QuestionFailureText="Sua resposta não pôde ser verificada. Por favor tente novamente." QuestionInstructionText="Responda a pergunta seguinte para receber sua senha." QuestionLabelText="Pergunta:" QuestionTitleText="Identificação confirmada" SubmitButtonText="Enviar" SuccessText="A sua solicitação de senha foi realizada com sucesso." UserNameFailureText="Nós não conseguimos localizar sua informação. Por favor tente novamente." UserNameInstructionText="Entre com seu Nome de Usuário para receber sua senha." UserNameLabelText="Usuário:" UserNameRequiredErrorMessage="Usuário requerido." UserNameTitleText="Esqueceu sua senha?" onsendingmail="PasswordRecovery1_SendingMail"> <SubmitButtonStyle BorderWidth="1px" Width="60px" /> </asp:PasswordRecovery>

Podemos verificar na Listagem 3 que se caso não convertemos em template, deixando o componente com uma das opções de layout padrão, o código HTML fica bem mais simplificado. Com o nosso componente podemos utilizar alguns eventos já predefinidos nele como, por exemplo, o evento SendingMail, que é disparado após a recuperação da senha, onde poderemos enviar um e-mail para o usuário com os dados de acesso dele.

Na Listagem 4 temos o código responsável por obter as informações do usuário e encaminhar o email.

Listagem 4. PasswordRecovery recuperando dados e enviando email

protected void PasswordRecovery1_SendingMail(object sender, MailMessageEventArgs e) { e.Cancel = true; string msg = string.Empty; // Obtém os dados do usuário MembershipUser user = Membership.GetUser(PasswordRecovery1.UserName, false); // Altera a senha do usuário para a senha “novasenha” user.ChangePassword(user.ResetPassword(), "novasenha"); // Grava as informações de alteração na base Membership.UpdateUser(user); // Montagem do email string corpo = string.Format(@"<html> <head> <title>Recuperação de Senha</title> </head> <body> <b>Portal de Serviços</b><br /> <p>Recebemos a sua solicitação de recuperação de senha.</p> <p>Usuário:  <b></b><br />Senha:  <b>novasenha</b></p> <p>Altere a sua senha o mais breve possível!</p> <br /> <br /> </body> </html> ", PasswordRecovery1.UserName); // Envia o email de recuperação. if (EnviarEmail(user.Email, "Solicitação de senha", corpo, string.Empty)) msg = " Email Enviado com sucesso"; else msg = " Não foi possivel enviar o email tente novamente"; if (!string.IsNullOrEmpty(msg)) ScriptManager.RegisterStartupScript(Page, Page.GetType(), "Alert", string.Format("alert(''); window.location.href='Index.aspx';", msg), true); }

Com esse código conseguimos efetuar a recuperação de senha para o determinado usuário e enviá-la por email de forma simples utilizando apenas um evento do componente PasswordRecovery.

NOTA: Esse método EnviarEmail deve funcionar de forma diferente do método já existente em sua aplicação responsável pelo envio de email.

Listagem 5. Verificando se o usuário está bloqueado

protected void btnValidarUser_Click(object sender, EventArgs e) { // Obtendo os dados do usuário a partir do seu username MembershipUser usuario = Membership.GetUser("nome usuário"); // Verificando o status do usuário a partir da sua propriedade isApproved if(usuario!= null && ! usuario.isApproved) { ClientScript.RegisterStartupScript( this.GetType(), "alert", "alert('Usuário com status bloqueado.');", true); } }

Com a Listagem 5 conseguimos verificar se determinado usuário encontra-se bloqueado ou não.

Com a chegada do Visual Studio 2013, a Microsoft adicionou um framework para gerenciar a identidade dos usuários chamado ASP.NET Identity. Esse veio para resolver algumas restrições e complicações que as versões anteriores do Membership possuíam.

Listagem 6. Direcionando Usuários para determinadas páginas após login

protected void LoginPrincipal_LoggedIn(object sender, EventArgs e) { // Obtendo os dados do usuário a partir do seu username MembershipUser usuario = Membership.GetUser("nome usuário"); if (usuario.Email.Contains("direcao")) Response.Redirect("~/WorkspaceDirecao.aspx"); else if (usuario.Email.Contains("financeiro")) Response.Redirect("~/WorkspaceFinanceiro.aspx"); else if (usuario.Email.Contains("comercial")) Response.Redirect("~/WorkspaceFinanceiro.aspx"); else Response.Redirect("~/Index.aspx"); }

Na Listagem 6 conseguimos fazer com que cada usuário, após o login, seja direcionado para uma tela específica. Como exemplo utilizamos o email do usuário para que, caso ele faça parte da direção, será direcionado para uma determinada tela, e assim por diante. Foi utilizado o evento LoggedIn do nosso componente Login, que é disparado após o usuário efetuar o login e conseguir permissão para acessa a aplicação.

O Membership é bom, mas têm algumas limitações encontradas:

Até o momento, a tecnologia mais utilizada e indicada pela própria Microsoft é o Membership, apesar do ASP.NET Identity ter um futuro promissor, quem sabe futuramente possa ser o carro chefe em termos de segurança das aplicações. Porém, existem outras opções ainda, como o OWIN e Katana.

O Membership foi desenvolvido para uso de aplicações Web, embora possa ser empregados sem dificuldades em outros tipos de aplicações .NET. Podemos concluir que o uso do Membership simplifica consideravelmente o desenvolvimento de aplicações mais seguras, pois não é necessário reinventar a roda como, por exemplo, criar um Login todo do zero. Essa é uma ferramenta muito importante, que contém um leque muito maior de funcionalidades.

Espero que tenham gostado do assunto.

Links

Introdução ao Membership
https://msdn.microsoft.com/pt-br/library/system.web.security.membership%28v=vs.110%29.aspx

Membership Class
https://msdn.microsoft.com/pt-br/library/system.web.security.membership%28v=vs.110%29.aspx

ASP .NET identity
http://www.asp.net/identity

Criptografia Hash
http://www.gta.ufrj.br/grad/07_1/ass-dig/TiposdeCriptografia.html

OWIN
http://www.asp.net/aspnet/overview/owin-and-katana

Artigos relacionados