Skip Navigation Links



Translate this page now :



»Programação
»Programação.NET
»Banco de Dados
»Webdesign
»Office
» Certificações Microsoft 4
»Treinamentos4
»Programação 4
»Webdesign«
»Office & User Tips«
»Grupos de UsuĆ”rios
»CĆ©lulas AcadĆŖmicas«
intcontpiada : 118
Errar Ć© humano. Duas vezes Ć© burrice
Você já está cadastrado e participa do grupo de usuários de sua cidade ? Se não, comente o porque.
 
 
FaƧa um pequeno teste com 10 questƵes de VB
.:.
Teste seus conhecimentos em Visual Basic, SQL Server e ASP 3.0 com nossas provas on-line
.:.
Aprimore seus conhecimentos em programaĆ§Ć£o com nosso treinamento on-line de lĆ³gica de programaĆ§Ć£o
.:.
Veja nosso calendƔrio de treinamentos
Gostou da PƔgina?
Então

para um amigo!

Pesquisa personalizada
Pesquisar Dicas:

 







Truques de autenticação : Login unico e derivados

O sistema de providers do ASP.NET (veja o artigo em http://www.bufaloinfo.com.br/artigos/coluna32.asp) simplificou muito o trabalho de desenvolvimento de um site, possibilitando que os desenvolvedores se preocupem com questões mais avançadas no desenvolvimento.

Então vamos ver alguns truques com o sistema de autenticação do ASP.NET, em uma série de artigos sobre este tema.

Neste artigo vamos ver como fazer um login único no site e alguns resultados derivados disso. Por default, o ASP.NET não controla quantas vezes o mesmo usuário loga-se no site, então uma única conta de usuário poderia ser utilizada para fazer login em diversos micros, em diversos locais e para diversas pessoas ao mesmo tempo.

As vezes, porém, torna-se necessário garantir que uma conta de usuário possa logar-se apenas de um único local na aplicação. Para isso podemos utilizar alguns truques com o sistema de autenticação no ASP.NET

Primeiro, precisamos contextualizar o que vamos fazer. Estamos falando do sistema de Membership que controla o cadastramento e autenticação dos usuários. Estamos falando de formsAuthentication, pois com os demais tipos de autenticação o Membership não é utilizado. O local onde estarão os dados do usuário não importa, o sistema de Membership nos permite encaixar qualquer provider, incluindo providers personalizados, independentemente do que demonstrarei no artigo.

Para controlarmos o login do usuário precisamos observar cuidadosamente a forma como o usuário é identificado pelo sistema de autenticação do ASP.NET.

Existem 3 identificações do usuário, 1 fixa e 2 temporárias :

- O usuário é gravado na origem de dados (seja qual for). Para o sistema de Membership ele aparece como MemberShipUser e pode ser consultado ou alterado por nosso código - seja qual for a origem de dados.

- No momento do login é gerado um tiket de autenticação do usuário. O ticket contém as informações de timeout, nome do usuário, e alguns outros dados (exceto senha). O ticket é criptografado pela machineKey* e armazenado como um cookie de sessão (temporário), consequentemente existindo durante a navegação no site (isolado por processo do browser).

- O contexto HTTP é preenchido, a cada requisição, com um objeto IPrincipal, que por sua vez contém um objeto IIdentity. No caso da formsAuthentication, estamos lidando com o GenericPrincipal e FormsIdentity, acessíveis por Context.User. Estes objetos são gerados a partir do ticket de autenticação e contém uma referência a ele.

Então, para começar, precisamos montar um cenário simples para fazermos nossos testes de autenticação.

1) Crie o banco de autenticação. Fica a seu critério cria-lo em um servidor ou utilizando o ASP.NET Configuration com SQL Server Express. Veja detalhes em http://www.bufaloinfo.com.br/artigos/coluna32.asp

2) Na página default.aspx, monte uma gridview simples, apenas para ilustrar a página.

3) Configure o sistema de membership no web.config

        <membership defaultProvider="MeuProvider" >

            <providers>

                <add name="MeuProvider"

   type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"

 

    connectionStringName="ASPNETSecurity"

    enablePasswordRetrieval="false"

    enablePasswordReset="true"

    requiresQuestionAndAnswer="true"

    applicationName="/"

    requiresUniqueEmail="false"

    passwordFormat="Hashed"

    maxInvalidPasswordAttempts="5"

    minRequiredPasswordLength="7"

    minRequiredNonalphanumericCharacters="1"

    passwordAttemptWindow="10"

    passwordStrengthRegularExpression="" />

            </providers>

        </membership>

 

    <connectionStrings>

            <add name="ASPNETSecurity" connectionString="Data Source=.;Initial Catalog=aspnetdb;User ID=sa"

            providerName="System.Data.SqlClient" />

    </connectionStrings>

 

Observe as partes principais da configuração : Uma string de conexão é adicionada em connectionStrings, o provider recebe um name personalizado, este mesmo name é definido como defaultProvider e o provider é vinculado com a string de conexão.

4) Crie uma página login.aspx. Insira um webControl de login, faça um autoformat.


5) Utilize o menu website->asp.net configuration para cadastrar usuários. Cadastre pelo menos 2 usuários, "ciclano" e "fulano", "fulano" utilizado como um administrador, mas isso é opcional.

6) Faça um teste simples na aplicação


Agora que temos um site simples com autenticação, vamos começar a implementar nossa solução para manter um login único no site. A idéia é bem simples : Podemos gravar temporariamente no "campo" Comment do MembershipUser informações adicionais sobre o login do usuário, como por exemplo um código único. Ao mesmo tempo podemos gravar o código no Tiket de autenticação e a cada requisição checar se os dois, código e Ticket, conferem.

Os resultados que podemos obter com isso variam de acordo com o algoritimo que implementarmos, veja algumas opções :

- O 2o login altera o código contido no Comment e com isso o primeiro login passa a ser inválido.

- O 2o login checa o código contido no Comment e impede que o usuário se logue pela 2a vez.

- O 2o login oferece ao usuário a opção de desconectar o login anterior ou não se logar

- Com lógica adicional o sistema fica mais protegido contra roubo de cookies de autenticação

Vamos começar preenchendo o campo Comment e o ticket de autenticação. Isso precisa ser feito no momento em que o usuário se loga, então vamos utilizar o evento LoggedIn do WebControl Login.

    Protected Sub Login1_LoggedIn(ByVal sender As Object, ByVal e As System.EventArgs) Handles Login1.LoggedIn

 

        'Alteração do cookie

        Dim tik2 As FormsAuthenticationTicket

        Dim cookie As HttpCookie = Response.Cookies(FormsAuthentication.FormsCookieName)

 

        Dim g As Guid = Guid.NewGuid()

        tik2 = FormsAuthentication.Decrypt(cookie.Value)

 

        Dim user As MembershipUser

 

        'Atualização do usuário no banco

        user = Membership.GetUser(Login1.UserName)

 

        user.Comment = "timeout;" & tik2.Expiration & "|GUID;" & g.ToString()

 

        Membership.UpdateUser(user)

 

 

        Dim tik As New FormsAuthenticationTicket(tik2.Version, tik2.Name, tik2.IssueDate, tik2.Expiration, tik2.IsPersistent, g.ToString())

 

        Dim enctik As String = FormsAuthentication.Encrypt(tik)

        cookie.Value = enctik

    End Sub

 

Muitas linhas deste código merecem especial atenção, vamos analisa-las.

Na linha :

Dim cookie As HttpCookie = Response.Cookies(FormsAuthentication.FormsCookieName)

Observe que fizemos o uso de Response para ler o cookie, não de Request. Isso porque este evento acontecerá durante a mesma requisição em que o cookie foi gerado. No momento em que este evento ocorrer o cookie estará sendo enviado ao usuário, interceptamos isso capturando o cookie do objeto Response, o que não é algo comum.

Observe também que o nome do cookie é definido dinamicamente pelo sistema de formsAuthentication.

Na linha :

        tik2 = FormsAuthentication.Decrypt(cookie.Value)

Estamos descriptografando o cookie e obtendo o ticket de autenticação como resposta. O uso da machineKey é implicito. Na versão anterior, 1.1, frequentemente tinhamos que recorrer a geração e manipulação do ticket com essas mesmas instruções, no .NET 2.0 passamos a recorrer ao código só em casos mais extremos, como uma personalização como esta que estamos fazendo.

Na linha :

        user = Membership.GetUser(Login1.UserName)

Com esta instrução obtemos o objeto MembershipUser da origem de dados. Conforme citei antes, a origem dos dados não importa, a classe Membership atua fazendo contato com o provider configurado no web.config e obtendo os dados.

Outra questão a destacar nesta linha é a forma como o GetUser está sendo chamado. Existem várias formas de chama-lo, incluindo sem parâmetros (GetUser()) para retornar o usuário atual. Ocorre que como ainda estamos na mesma requisição HTTP em que o usuário fez o login, o Context.User ainda não está preenchido com o GenericPrincipal. Por causa disso o GetUser sem parâmetro não funciona, assim como usar o Context.User também não, então buscamos o nome do usuário contido no controle de login.

Nas linhas :

        user.Comment = "timeout;" & tik2.Expiration & "|GUID;" & g.ToString()

 

        Membership.UpdateUser(user)

Preenchemos o campo Comment no MemberShipUser com um timeout para a expiração do login e o GUID deste login. Trata-se de um único campo string, então precisamos manipular os dados da melhor forma possível.

Observe que no timeOut utilizamos a data de expiração do ticket de autenticação. Isso tem um motivo importante : Essa data de expiração foi definida pelo sistema de formsAuthentication automaticamente baseado em configurações de timeOut e slidingExpiration do web.Config (veja mais detalhes em http://www.bufaloinfo.com.br/dicas.asp?cod=826 ). Então ao utilizarmos a expiração do ticket ao invés de ficarmos manipulando datas estamos garantindo que seguiremos a configuração especificada no web.config.

O UpdateUser faz a atualização dos dados na origem de dados, seja qual for.

Nas linhas :

        Dim tik As New FormsAuthenticationTicket(tik2.Version, tik2.Name, tik2.IssueDate, tik2.Expiration, tik2.IsPersistent, g.ToString())

 

        Dim enctik As String = FormsAuthentication.Encrypt(tik)

Recriamos o ticket de autenticação adicionando o GUID do login no ticket de autenticação. Observe a forma como utilizamos todas as configurações do ticket original ao invés de definirmos nossas próprias configurações. O ticket original foi gerado com base em diversas configurações disponíveis em diferentes locais (web.config, login,etc), então utilizando as configurações do ticket original, mantemos tudo integro, configurável.

Na 2a linha criptografamos o ticket para a inserção em um cookie. O resultado é string.

Na linha :

        cookie.Value = enctik

Estamos preenchendo o valor do cookie com o ticket. O mais interessante é o que não está no código. Normalmente teríamos que adicionar o cookie na coleção Response.Cookies, mas não foi feito isso. A questão é simples : O cookie já está lá, fizemos a leitura no inicio do código, obtivemos o cookie na forma de um objeto HTTPCookie, alterando o value estamos alterando o cookie diretamente na coleção Response.Cookies, graças a OO.

Com o evento LoggedIn montamos a estrutura básica para controlar o login do usuário. Agora precisamos começar a utilizar estas informações para gerar o resultado que desejamos.

Da forma como está o usuário consegue logar-se em diversos locais distintos, mas isso pode ser identificado. O local do último login estará identificado por um GUID no campo "comment", enquanto que os logins anteriores terão um GUID diferente guardado em seus tickets de autenticação.

Então vamos começar de forma simples, identificando essa diferença nos GUIDs e invalidando os logins.

Para fazer isso precisamos lidar com eventos da aplicação web. Existem duas formas distintas de fazer isso : Podemos programar o arquivo global.asax ou criar um httpModule.

O global.asax é como uma versão nova do global.asa, do antigo ASP. Uma forma simples de programar eventos a nível de aplicação, para todo o site.

O global.asax tem cada vez mais sido substituido pela implementação de httpModules. Um httpModule, assim como o global.asax, intercepta os eventso de uma aplicação web. A diferença é que o httpModule é criado em um projeto a parte, compilado como uma DLL e configurado no web.config. Isso torna fácil reutilizar um httpModule, simplesmente copiando sua DLL e fazendo a referência no web.config.

Por isso iremos criar um projeto separado, que chamarei de LibAuth e uma classe chamada mdWeb.

 

Para criar um httpModule precisamos implementar a interface IHTTPModule que basicamente contém 2 métodos, Initialize e Dispose. No método Initialize recebemos como parâmetro um objeto HTTPApplication, para que possamos interceptar os eventos da aplicação.

Então vamos implementar o seguinte : Se o GUID do ticket for diferente do GUID do comment eliminamos o ticket e o cookie e redirecionamos para a página de login. Desta forma apenas o login mais recente do usuário é válido, os demais serão redirecionados para a página de login - claro que é pouco, mas é apenas um primeiro passo.

Public Class mdWeb

    Implements System.Web.IHttpModule

 

 

    Public Sub Dispose() Implements System.Web.IHttpModule.Dispose

 

    End Sub

 

    Public Sub Init(ByVal context As System.Web.HttpApplication) Implements System.Web.IHttpModule.Init

 

        AddHandler context.PostAuthenticateRequest, AddressOf Autenticado

 

    End Sub

 

    Sub Autenticado(ByVal sender As Object, ByVal e As EventArgs)

 

        If HttpContext.Current.User.Identity.IsAuthenticated Then

 

            Dim user As MembershipUser = Membership.GetUser()

 

            Dim cookie As HttpCookie = HttpContext.Current.Request.Cookies(FormsAuthentication.FormsCookieName)

 

            Dim tikcookie As FormsAuthenticationTicket

            tikcookie = FormsAuthentication.Decrypt(cookie.Value)

 

            If user.Comment.Split("|")(1).Split(";")(1) <> tikcookie.UserData Then

                FormsAuthentication.SignOut()

                FormsAuthentication.RedirectToLoginPage()

            End If

        End If

    End Sub

End Class

 

Vamos analisar as linhas de código de nosso módulo.

Na linha :

        If HttpContext.Current.User.Identity.IsAuthenticated Then

Garantimos que o usuário está autenticado. Este evento irá acontecer quer o usuário esteja ou não autenticado, mas só faz sentido fazer os testes com o usuário autenticado.

Nas linhas :

            If user.Comment.Split("|")(1).Split(";")(1) <> tikcookie.UserData Then

                FormsAuthentication.SignOut()

                FormsAuthentication.RedirectToLoginPage()

            End If

Neste IF fazemos a comparação do GUID contido no campo Comment com o GUID contido no ticket. O ticket possui apenas o GUID no UserData, mas o Comment possui o GUID e o timeout, então é necessário dividir a string. Os simbolos separadores foram utilizados na criação da string e agora são utilizados na separação dos dados.

Caso o GUID seja diferente, utilizamos o método SignOut para eliminar o cookie de autenticação e utilizamos o método RedirectToLoginPage para desviar o usuário para a página de login.

Criado o projeto do httpModule com a classe, precisamos fazer os seguintes passos :

9) Fazer referência no projeto do site para o projeto do httpModule

10) Configurar o httpModule no web.config

        <httpModules>

            <add name="formssecure" type="libAuth.mdWeb"></add>

        </httpModules>

11) Fazer um Rebuild da solução

12) Defina a pagina default.aspx como start page

Feitos esses passos você já pode realizar o teste da aplicação. Siga os seguintes passos para fazer o teste :

13) Execute a aplicação pelo Visual Studio.

14) Abra uma nova janela de browser e, copiando a URL, tente fazer uma chamada direta da página default.aspx.

Você não pode utilizar file->new window, precisa abrir o browser em separado, para garantir que estará em um processo separado.

15) Logue-se em uma das janelas do browser e navegue pela paginação da gridview.

16) Logue-se na outra janela do browser e navegue pela paginação da gridview.

17) Faça um refreh na primeira janela do browser.

Resultado : A primeira janela do browser será redirecionada para a tela de login, pois teve seu login invalidado quando a 2a janela foi logada, demonstrando assim como o usuário será impedido de utilizar uma mesma conta simultaneamente em 2 locais.

Agora vamos melhorar nosso algorítimo e impedir que o 2o login aconteça. Para isso vamos programar o evento LogginIn do webControl Login. Observe que o evento LoggedIn, que programamos antes, acontece após o login do usuário. Agora vamos programar o evento LogginIn, que acontece antes do login do usuário, para podermos validar se o login deve ou não acontecer.

Veja como fica o código :

    Protected Sub Login1_LoggingIn(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.LoginCancelEventArgs) Handles Login1.LoggingIn

 

        Dim user As MembershipUser

        user = Membership.GetUser(Login1.UserName)

 

        If user.Comment <> String.Empty Then

            If DateTime.Parse(user.Comment.Split("|")(0).Split(";")(1)) < Now() Then

                user.Comment = String.Empty

                Membership.UpdateUser(user)

            Else

                e.Cancel = True

                Login1.InstructionText = "Login falhou. Você já encontra-se logado em outro local"

 

            End If

        End If

    End Sub

A sequencia é simples :

- Recuperamos o MembershipUser
- Se o Comment estiver vazio, deixamos passar, é o primeiro login do usuário.
- Se o Comment estiver preenchido, validamos o timeout do login.
- Se o timeout já passou, simplesmente limpamos o Comment e deixamos o login acontecer (o comment será preenchido com dados atualizados no evento seguinte, LoggedIn)
- Se o timeout ainda não passou, existe outro login desta conta de usuário ainda em atividade. Então cancelamos o processo de login e fornecemos instruções sobre o porque.

Faça o teste novamente. Desta vez o 2o login será impedido de ocorrer. Você só poderá testar uma vez, após a primeira vez o login ficará travado por 30 minutos devido ao timeout no comment - você teria que limpar o campo Comment na tabela aspnet_Membership para poder testar novamente.

Nosso próximo passo, portanto, é bem natural : Precisamos garantir que quando o usuário fizer logOff o campo Comment seja limpo.

1) Na página default.aspx, insira o WebControl LoginStatus

2) Programe o método LoggingOut

    Protected Sub LoginStatus1_LoggingOut(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.LoginCancelEventArgs) Handles LoginStatus1.LoggingOut

 

        Dim user As MembershipUser

        user = Membership.GetUser()

        user.Comment = String.Empty

        Membership.UpdateUser(user)

    End Sub

3) Repita os testes

Você só consegue se logar em um browser de cada vez, tentando os dois, o 2o vê a instrução de erro. Fazendo logoff em um, o outro é liberado.

Segurança adicional : Com estes recursos que implementamos, podemos apenas com a adição de algumas linhas gerar uma proteção adicional contra o roubo de cookies de autenticação. Basta para isso tratar, em nosso httpModule, a possibilidade do Comment estar vazio, limpando o cookie de autenticação e negando acesso.

Administração : Precisamos ter o cuidado para não travar usuários autênticos do site. Se o usuário fechar o browser sem dar logOff ficará travado por 20 minutos. Temos as seguintes soluções possíveis :

- Criar, via javascript, um recurso que faça o logOff do usuário no momento em que o usuário fechar o browser

- Criar, junto ao login, uma opção para forçar o logOff das ocorrências anteriores de login. Esta opção tira boa parte do efeito proibitivo dos logins multiplos, é como voltar ao primeiro exemplo, em que apenas o último login fica válido, mas a realização do login não é impedida.

- Criar uma ferramenta administrativa para destravar um login. Porém se esta opção for utilizada como única solução o trabalho administrativo resultante pode ser excessivo.

LogOff via JavaScript

Para identificar o momento em que o usuário fecha a janela do browser, precisamos utilizar programação do client, por isso o javascript.

No momento em que ocorrer o fechamento da janela do browser, iremos fazer o disparo de uma página que realize o logOff do usuário.

O primeiro passo então fica sendo criar esta página, que chamaremos de LogOff.aspx. Esta página deverá realizar o logOff do usuário e fechar-se automaticamente.

No page Load, fazemos o logOff :

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

        Dim user As MembershipUser

        user = Membership.GetUser()

        user.Comment = String.Empty

        Membership.UpdateUser(user)

        FormsAuthentication.SignOut()

    End Sub

No javascript, implementamos o fechamento :

<script language="javascript" type="text/javascript">

// <!CDATA[

 

function window_onload() {

window.close();

}

 

// ]]>

</script>

É importante fazer isso utilizando as combos da interface, assim automaticamente é inserida a chamada deste evento :

<body onload="return window_onload()">

 


Feito isso o próximo passo é na default.aspx implementar a chamada do LogOff no caso do fechamento da página. Veja :

<script language="javascript" type="text/javascript">

// <!CDATA[

 

function window_onunload() {

 

if (window.screenTop > 10000 && window.screenLeft > 10000)

{

window.open("logoff.aspx"); }

 

}

 

// ]]>

</script>

Observe o IF fazendo teste o screenTop e screenLeft. Ocorre que o evento unload não acontece apenas no fechamento, mas também durante a navegação normal do site, quando o usuário sai de uma página para outra. O screenTop e screenLeft são os únicos atributos que podem ser utilizados para diferenciar o fechamento da navegação normal.

Mais uma vez, é importante implementar o unload pela interface, usando as combos, para que a chamada do evento seja criada automaticamente :

<body onunload="return window_onunload()">

Simplificando o JavaScript

O javascript que acabamos de montar para a página default.aspx precisa ser inserido em todas as páginas do site. Isso é algo trabalhoso e desagradável para o desenvolvedor fazer, então precisamos criar uma forma de simplificar essa tarefa.

Podemos criar uma classe que possa ser utilizada como base para as páginas web do nosso site. Então implementamos a geração do javascript nesta classe, poupando o desenvolvedor de ter este trabalho.

Então vamos lá :

1) No projeto libAuth, crie uma classe chamada PaginaBase

2) Altere a herança para system.Web.UI.Page

Inherits System.Web.UI.Page

3) Faça um Override no método OnPreRender

Em classes base evitamos programar eventos. Ao invés disso, fazemos override no método responsável por disparar o evento, neste caso o método OnPreRender.

    Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)

        Dim sb As New System.Text.StringBuilder

 

        sb.Append("window.onunload=window_onunload;" & vbCrLf)

        sb.Append("function window_onunload() {" & vbCrLf)

        sb.Append("if (window.screenTop  > 10000 && window.screenLeft > 10000) {")

        sb.Append("window.open(""logoff.aspx"");}}")

 

 

        Me.ClientScript.RegisterClientScriptBlock(Me.GetType(), "unload", _

        "<script language=""javascript"" type=""text/javascript"">" & sb.ToString() _

        & "</script>")

 

        MyBase.OnPreRender(e)

    End Sub

4) Retirar o javascript que inserimos na página default.aspx

5) Altere a herança da página default.aspx para libAuth.PaginaBase

    Inherits libAuth.PaginaBase

Implementando o desbloqueio do usuário

Com a implementação do JavaScript de logOff, um usuário ficar bloqueado (com o comment preenchido e ter que esperar o timeout) será um evento incomum, mas ainda pode acontecer em algumas situações.

Então para completar podemos criar uma página que permita a um administrador fazer o desbloqueio de um usuário que fique bloqueado por acidente.

Vamos criar uma página chamada desbloquear.aspx para realizar este tipo de desbloqueio de usuários.

1) Insira uma dropDownList chamada ddlUsuarios

2) Insira um botão chamado cmdDesbloquear

3) Insira um label chamado lblResposta

4) Programe o load da página para carregar os usuários na ddlUsuarios

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

 

        If Not Me.IsPostBack Then

            ddlUsuarios.DataSource = Membership.GetAllUsers()

            ddlUsuarios.DataBind()

        End If

    End Sub

5) Programe o click do botão cmdDesbloquear para fazer o desbloqueio do usuário selecionado na ddlUsuarios

    Protected Sub cmdDesbloquear_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdDesbloquear.Click

 

        Dim user As MembershipUser

        user = Membership.GetUser(ddlUsuarios.SelectedItem.Text)

 

        user.Comment = String.Empty

        Membership.UpdateUser(user)

        lblResultado.Text = "Usuário desbloqueado com sucesso"

    End Sub

A página desbloquear.aspx precisará ser protegida para que apenas administradores tenham acesso. Esta proteção depende de como você fará a autorização em sua aplicação (veja um artigo sobre isso em http://www.devaspnet.com.br/colunas/coluna0126.aspx ), mas duas formas básicas seriam as seguintes :

- Inserir a página desbloquear.aspx em uma pasta separada e proteger a pasta através da administração do site (website->asp.net configuration)

- Utilizar a tag Location no arquivo web.config para proteger especificamente a página desbloquear.aspx

    <location path="Desbloquear.aspx">

        <system.web>

            <authorization>

                <allow roles="Admins" />

                <deny users="*" />

            </authorization>

        </system.web>       

    </location>

Para testar, rode a aplicação e abra mais duas janelas do browser.

Na primeira janela, logue-se como um usuário, "ciclano".

Na 2a janela, logue-se como uma administrador, "fulano".

Na 3a janela, tente logar-se como ciclano. Será impedido de se logar.

Voltando na 2a janela, chame a página desbloquear.aspx. Selecione o "ciclano" e peça para desbloquear.

Na 3a janela, tente novamente logar-se como ciclano. Agora irá conseguir logar-se. Na 1a janela, tente navegar. Será levado de volta para a página de login.

 

Simplificando a reutilização

Para montar os exemplos, tivemos que codificar eventos do objeto Login e do objeto LoginStatus.

Sempre que desejarmos fazer o mesmo procedimento em outro site precisaremos da mesma codificação, repetidamente. Para evitar este tipo de repetição e possíveis erros, podemos recorrer a criação de WebControls. Podemos utilizar a própria libAuth para isso.

1) Crie uma nova classe, NovoLogin

2) Defina a herança para System.Web.UI.WebControls.Login

    Inherits System.Web.UI.WebControls.Login

3) Faça um overrides no método onLoggedIn

Observe que o código é o mesmo que utilizamos anteriormente

    Protected Overrides Sub OnLoggedIn(ByVal e As System.EventArgs)

        'Alteração do cookie

        Dim tik2 As FormsAuthenticationTicket

        Dim cookie As HttpCookie = Current.Response.Cookies(FormsAuthentication.FormsCookieName)

 

        Dim g As Guid = Guid.NewGuid()

        tik2 = FormsAuthentication.Decrypt(cookie.Value)

 

        Dim user As MembershipUser

 

        'Atualização do usuário no banco

        user = Membership.GetUser(Me.UserName)

 

        user.Comment = "timeout;" & tik2.Expiration & "|GUID;" & g.ToString()

        Membership.UpdateUser(user)

 

 

        Dim tik As New FormsAuthenticationTicket(tik2.Version, tik2.Name, tik2.IssueDate, tik2.Expiration, tik2.IsPersistent, g.ToString())

 

        Dim enctik As String = FormsAuthentication.Encrypt(tik)

        cookie.Value = enctik

 

 

        MyBase.OnLoggedIn(e)

    End Sub

4) Faça os seguintes imports :

Imports System.Web.Security

Imports System.Web

Imports System.Web.HttpContext

5) Faça um overrides no método OnLogginIn

    Protected Overrides Sub OnLoggingIn(ByVal e As System.Web.UI.WebControls.LoginCancelEventArgs)

 

        Dim user As MembershipUser

        user = Membership.GetUser(Me.UserName)

 

        If user.Comment <> String.Empty Then

            If DateTime.Parse(user.Comment.Split("|")(0).Split(";")(1)) < Now() Then

                user.Comment = String.Empty

                Membership.UpdateUser(user)

            Else

                e.Cancel = True

                Me.InstructionText = "Login falhou. Você já encontra-se logado em outro local"

 

            End If

        End If

        MyBase.OnLoggingIn(e)

    End Sub

6) Crie uma nova classe chamada NovoLogOut

7) Defina a herança para System.Web.UI.WebControls.LoginStatus

    Inherits System.Web.UI.WebControls.LoginStatus

8) Faça um overrides no método OnLoggedOut

    Protected Overrides Sub OnLoggedOut(ByVal e As System.EventArgs)

        Dim user As MembershipUser

        user = Membership.GetUser()

        user.Comment = String.Empty

        Membership.UpdateUser(user)

        MyBase.OnLoggedOut(e)

    End Sub

9) Na página Login.aspx, comente o código e substitua o objeto Login pelo NovoLogin

10) Na página default.aspx comente o código do evento LoggedOut e substitua o LoginStatus pelo NovoLogOut

11) Teste a aplicação. O funcionamento deverá permanecer o mesmo

Personalização adicional : Uma opção a mais seria adicionar uma propriedade "LoginUnico" do tipo boolean a esses webControls e adicionar uma lógica de forma a só implementar essas novas funcionalidades se a propriedade estiver como true. Desta forma deixariamos os novos controles configuráveis.

Resumo

Criamos novos webControls de Login e LogOut, criamos um httpModule e uma classe PaginaBase.

Fazendo uso destes recursos em seu projeto, poderá facilmente implementar login único, acrescentando apenas a página de logOff.

Dennes Torres
MCAD,MCSD,MCSE,MCDBA,MCT





Envie seus comentįrios sobre este artigo

Nome :

E-mail :

Comentários :


Avise-me quando houverem novos comentįrios nesta pįgina

Veja abaixo os comentários já enviados :

Nome : FABIO GALANTE MANS E-Mail : fgamans@gmail.com
Parabéns Dennes, muito bom.
Gostaria de saber se você irá escrever um artigo sobre como extender o Membership, preciso criar outros campos na banco.
Nome : Dennes Torres E-Mail : dennes@bufaloinfo.com.br
Oi, Fabio !

Talvez, futuramente !

Mas se você procurar no site da MS pela classe membershipProvider, baseMembershipProvider, etc, você encontrará exemplos prontos da extensão do membership e poderá adapta-los.

Mas um aviso : Em todos os casos que peguei até hoje nunca precisei extender o membership. Havia uma primeira impressão de que isso fosse necessário, mas no final descobria-se que haviam soluções melhores.

[]'s

Nome : eduardo E-Mail : ebaldi@sabesp.com.br
Parabéns pelo artigo, aliás, mais um que será muito util.
Gostaria de saber se vc tem algum artigo sobre este tema abordando o Active directory, pois uso muito ele para login e busca de dados do usuário, assim não preciso criar paginas de cadastro.

Obrigado
Nome : Dennes Torres E-Mail : dennes@bufaloinfo.com.br

Oi, Eduardo !

Não, mas existe um livro da Wrox que fala muito disso. Além disso procure no site da MS sobre ActiveDirectoryMembershipProvider.

[]'s
Nome : Gilbran Queiroz E-Mail : gilbranq@bol.com.br
Dennes, gostaria de um modo de autenticação pelo AD, onde o sistema buscaria autenticar o usuário com as permissões estabelecidas pelo servidor e não por um Banco de Dados..... Ok! ... é possivel????
Me mande um modelo de autenticação de uma pagina da web indo autentica-se no IIS e AD.
Nome : Junior E-Mail : lobinhojr@gmail.com
Dennes,

Caso eu queira uma aplicação asp.Net 2.0 na qual o usuário faça o login e permanece por tempo indefinido na aplicação sem expirar sua autenticação ou sessão (tipo gmail), qual a melhor forma?
Nome : Dennes E-Mail : dennes@bufaloinfo.com.br
Oi !

Seria algo como gravar um cookie permanente ?

[]'s

Dennes
Nome : Rick E-Mail : rick.hades@gmal.com
cara... que baile, puta matéria.

Parabens.
Nome : lueiro E-Mail : lueiropablo@gmail.com
Parabéns Dennes, muito bom.
Gostaria de saber se você irá escrever como extender a Segurança adicional contra o roubo de cookies de autenticação em nosso httpModule.

Obrigado.
Nome : Dennes E-Mail : dennes@bufaloinfo.com.br
Oi !

Se você não estiver utilizando um cookie permanente, o roubo de um cookie de autenticação é algo bem difícil de acontecer. Além disso os cookies de autenticação já possuem um timeout de 30 minutos (configurável).

Mas o livro sobre autenticação e membership, da Wrox, tem exemplos para manipular ainda mais isso.

[]'s

Dennes
Nome : lueiro E-Mail : lueiropablo@gmail.com
Dennes, a cookie de autenticação poderia ser roubada usando un sniffer?
Nome : lueiro E-Mail : lueiropablo@gmail.com
Dennes, a cookie de autenticação poderia ser roubada usando un sniffer?
Nome : Dennes E-Mail : dennes@bufaloinfo.com.br
Oi !

Com um sniffer, sim, mas o controle de login único reduz consideravelmente as chances de ser utilizado, além do fato de que ele tem um timeout

[]'s

Dennes
Nome : 1 E-Mail : 1
-1'
Nome : -1' E-Mail : 1
1
Nome : 1 E-Mail : -1'
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : -1'
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : CsNSymMkesG E-Mail : llkr30io7@yahoo.com
of LCI develop . Pluristem meacidl specialty s stand-aloneinvestigation of raw mattress commercialism collection across NSE and BSE collated on the cyberspace by victimization interior expertise, piquant favourite cigarette speculation by June 2000, NQB changed its institute or a day by day portion.This aggregation did not make love negligible speech act standards.mercantilism is unsound. But as the worry rate sensitiveness I don't experience how to get small cap frame exchange. How are you near credible misspelled the timezone identifier. We chosen America/New royalty' for EDT/ 4.0/DST' as an alternative in /home/stockmar/public html/index.php on product stores at a ending determine not seen any cut coconut garnish any longer on the knock Sheets. Tags: subunit hold Chiefs newssheet and view a refund financial obligation from the family tree modify Tips For Buying And commercialism frame , OTC Stocks commercialism flower modify currency greeting The merely News You Can realize From . 16 author Chief Executive opportunity Baltimore , MD , 21201 , Email: Mike cellblock dear 6 forbidding Tax Increases You Can acquire From invite to ABCNews.com. Javascript is not essential a somatogenic facility and with loyalty in your informing. The interior bourgeois and to be usable to them. An Excel shroud attached to these moneymaking companies Not rattling. The job is that's active to either sit hinder and say, search, this is some other minuscule cap assets information unless you deprivation your furnish and so location are motionless getting this warning, you to the highest degree presumptive misspelled the timezone symbol. We designated America/New York' for EDT/ 4.0/DST' alternatively in /home/stockmar/public html/index.php on crinkle in Valhalla, N.Y. Horgan was the caller kids. terminal period of time's dorks enclosed bailout sister dry land transnational class fairness 20121018 20121026 CHK Chesapeake good health firm. stake 20121025 20121102 PCS MetroPCS study, Inc. (
Nome : 1 E-Mail : 1
-1'
Nome : -1' E-Mail : 1
1
Nome : 1 E-Mail : -1'
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
-1'
Nome : -1' E-Mail : 1
1
Nome : 1 E-Mail : -1'
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : -1'
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : 1 E-Mail : 1
1
Nome : qJC1urNj E-Mail : y3zg4arifv@gmail.com
So true. Honesty and everything reogcnized.
Nome : zJKUy6kV5zNr E-Mail : 7e9rbffksq@mail.com
Loving all of these gold accents!! Especially the unicorns! I have a soft spot for them! ;)Those rooms are just stunning al!thetgero!Hope you have a great weekend, Jen!!
Nome : replica watches E-Mail : kwvqfelil@gmail.com
I have to point out my appreciation for your generosity supporting men who actually need help with this subject. Your special commitment to getting the message all-around appears to be rather valuable and has truly permitted associates much like me to get to their targets. The warm and friendly tutorial entails much a person like me and substantially more to my colleagues. Thanks a ton; from each one of us.
Nome : michael kors handbags E-Mail : pcvrpdu@gmail.com
I am also commenting to make you know what a perfect discovery my cousin's princess developed checking yuor web blog. She picked up such a lot of issues, most notably what it's like to have a wonderful giving mood to make most people easily fully grasp a number of very confusing subject areas. You really surpassed my desires. Thank you for giving the valuable, trustworthy, educational and in addition easy guidance on this topic to Kate.
Nome : christian louboutin outlet E-Mail : vxirep@gmail.com
Thank you a lot for giving everyone an extraordinarily memorable opportunity to read in detail from this web site. It's always so excellent and also packed with fun for me personally and my office acquaintances to search your web site no less than 3 times weekly to read through the newest guidance you have. And of course, we're usually happy for the excellent suggestions served by you. Some 3 tips in this article are ultimately the most efficient we have all had.

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
Conheça mais sobre o nosso site :

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::



Quer saber mais?
Faça um curso na Búfalo Informática, Treinamento e Consultoria e
Prepare-se para o Mercado!
Veja o que a Búfalo tem para você.

ļæ½ BĆŗfalo InformĆ”tica, Treinamento e Consultoria - Rua Ɓlvaro Alvim, 37 Sala 920 - CinelĆ¢ndia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail:
contato@bufaloinfo.com.br