sexta-feira, 6 de julho de 2007

Autenticação em Windows Form e controle de acesso a métodos.

Ola pessoal, andei sumido com alguns problemas no PC e alguma falta de tempo, mas hoje eu vou falar de um assunto que não vejo ser muito explorado talvez pela moda de tudo ser aplicação web, nada contra elas, muito pelo contrario eu gosto muito delas mas que há uma certa moda de fazer aplicações web para vender uma imagem de “moderno” isto tem, mas o assunto não e este, o assunto e autenticação para Windows form, pretendo explorar a infra-estrutura de segurança do .Net Framework.

Coisa muito simples basicamente, vamos autenticar o nosso usuário normalmente como você já faz sendo que iremos informar a aplicação deste resultado e deixar que ela gerencie este acesso de acordo com o desejado. Para isto vamos fazer uso de duas interfaces do .Net que são IIdentity e IPrincipal,então mão na massa.

Primeiro vamos criar uma classe que eu chamei de Identificacao nesta classe vamos implementar a interface IIdentity, esta classe sera justamente isto uma identidade e a interface implementa o que uma identidade do sistema tem que ter. o codigo da implementação da interface e este logo a baixo da declaração da classe.

Public Class Identificacao
Implements System.Security.Principal.IIdentity

Agora o visual studio deve ter criado os metodos da interface vamos tratar de um de cada vez.

O primeiro deles e o AuthenticationType, para nos ele não e muito importante para a eutenticação em si, ele e apenas o tipo de autenticação usada, e util se vc criar varios tipos de autenticação e quiser disquir os tipo que você criou.eu coloquei o um texto qualquer pro exemplo da seguinte forma.

Public ReadOnly Property AuthenticationType() As String Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return "Autenticação Windows Form Personalizada"
End Get
End Property

Depois vem o IsAuthenticated, este metodo e o metodo que ira informar se esta identificação e autenticada ou não então criamos uma variavel privada _ IsAuthenticated do tipo booleano para ser o retorno e o codigo da propriedade fica assim.

Public ReadOnly Property IsAuthenticated() As Boolean Implements System.Security.Principal.IIdentity.IsAuthenticated
Get
Return _IsAuthenticated
End Get
End Property

Por ultimo vem o Name que como vocÊ já deve esta imaginando e o nome do usuario, como em IsAuthenticated nos criamos uma variavel privada _name do tipo string para o retorno da propriedade que ficou assim.

Public ReadOnly Property Name() As String Implements System.Security.Principal.IIdentity.Name
Get
Return _Name
End Get
End Property


Bem, agora que resolvemos os métodos da interface vamos criar mais algumas coisas que vão nos ajudar na autenticação, primeiro vamos criar uma propriedade Role que vai nos auxiliar para identificar o papel do nosso usuário ela será do tipo BuiltInRole que um Enum que lista os papais gerenciados pelo .Net. para isto vamos criar uma variavel privada _Role para o retorno , o codigo da propriedade fica como abaixo.

Public ReadOnly Property Role() As ApplicationServices.BuiltInRole
Get
Return _Role
End Get
End Property

Agora vamos criar uma função para autenticar o nosso usuario, aqui não vou entrar em meritos de banco segurança e outras coisas por se um exemplo, na verdade aqui você poderar copiar e colar a função que você usa para autenticar normalmente deste que com ela você consiga preencher as informações da indentificação no passo seguinte, vale a pena dar uma olhada no help que tem um exemplo bem bacana com hash la.Mas aqui vamos por um codigo direto para autenticar João e Maria onde João e o Administrador e Maria e um usuario comum. Vou por a função para retornar a Role que para o exemplo e mais simples, mas nada o impede de retornar o verdadeiro ou falso ou até mesmo uma estrutura já que no mundo real isto veria de um banco e com mais informações provavelmente. O código de autenticação esta ai.

Private Function IsValidLogin(ByVal Login As String, ByVal PassWord As String) As ApplicationServices.BuiltInRole
Dim saida As ApplicationServices.BuiltInRole
If Login = "joao" And PassWord = "12345" Then
saida = ApplicationServices.BuiltInRole.Administrator
ElseIf Login = "maria" And PassWord = "54321" Then
saida = ApplicationServices.BuiltInRole.User
Else
saida = ApplicationServices.BuiltInRole.Guest
End If
Return saida
End Function

Agora vamos fazer o nosso construtor que terá como argumentos o Login e a Senha do nosso usuário e fará a chamada a nossa função de autenticação.O código e bem simples, se a função retornar um guest vamos assumir que ele não foi autenticado já que não nos interessa aqui usuários visitantes o IsAuthenticated e igual a falso e o name e em vazio , do contrario setamos o IsAuthenticated como true e o Name como o login do usuario.

Sub New(ByVal Login As String, ByVal PassWord As String)
_Role = IsValidLogin(Login, PassWord)
If _Role = ApplicationServices.BuiltInRole.Guest Then
_IsAuthenticated = False
_Name = ""
Else
_IsAuthenticated = True
_Name = Login
End If
End Sub


Com isto a nosso classe de identidade esta pronta, agora temos que fazer com o que o sistema a reconheça, para isto temos que criar mas uma classe que vai implementar a interface IPrincipal,a chamaremos de PrincipalIdentificacao ela sera responsavel por incapsular a nosso intentificação para que seja informada ao aplicativo que ela e a identificação principal do usuario do sistema. A declaração da implementação dela e como se segue.

Implements System.Security.Principal.IPrincipal

Você deve ter notadado que foi declarada uma propriedade Identity que e do tipo IIdentity, que não por coincidência e do mesmo tipo que a nossa classe identificacao.E ela que ira retornar a nossa identificação pra o framework, para isto vamos criar uma variavel privada da nossa classe para o retorno da propriedade logo abaixo do implements escrea a declação a baixo.

Private _Identity As Identificacao

E autere a propriedade identity de maneira que fique assim.

Public ReadOnly Property Identity() As System.Security.Principal.IIdentity Implements System.Security.Principal.IPrincipal.Identity
Get
Return _Identity
End Get
End Property

O metodo IsRole acho que o nome já e autodescrtivo e uma função que testa se o usuario e da role que foi informada retornando um verdadeiro ou falso o codigo e seguinte.

Public Function IsInRole(ByVal role As String) As Boolean Implements System.Security.Principal.IPrincipal.IsInRole
Return role = _Identity.Role.ToString
End Function

E agora vamos criar um construtor para entrarmos com o login e a senha como argumentos, o construtor só ira instanciar uma itentificação com basse nestes parametros.

Sub New(ByVal Login As String, ByVal PassWord As String)
_Identity = New Identificacao(Login, PassWord)
End Sub


Pronto com isto já temos a infra-esturura para autenticação, construar agora uma janela de login normal o de sempre dois textbox dois botôes o de constume.E crie um form para ser acessado casso o login seja realizado com sucesso eu chamei este form de frmMetodosTesteAcesso

De um duplo click no botão do ok e escreva o seguinte.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Autenticacao As New PrincipalIdentificacao(Me.txtlogin.Text, Me.txtsenha.Text)
If Autenticacao.Identity.IsAuthenticated = True Then
Threading.Thread.CurrentPrincipal = Autenticacao
Dim form As New frmMetodosTesteAcesso
form.Show()
Else
MessageBox.Show("Login ou Senha invalida, usuario não autorizado", "Falha de Login", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End If
End Sub

Vamos la explicando, criamos uma instancia de PrincipalIdentificacao passando o login e a senha no nosso usuario,então testamos se este usuario conseguiu se altenticar conforme o que foi programado em nossa classe identificacao que e ela quem estamos acessando atraves da propriedade Identity, em caso afirmativo substituimos a indentificação do usuario da thead principal do aplicativo pela nossa identificação, e abrimos o formulario se não negamos o acesso.

A esta autura você deve esta se perguntando, nossa tanto trabalho so para isto?? , calma pessoa de pouca fé, a melhor parte vem agora.

Com isto agora podemos ter acesso as informações da indentificação do usuario logado em qualquer parte da nossa aplicação. Para demostrar isto vamos até o frmMetodosTesteAcesso, crie dois botão nele.

Va au codigo do formulario e vamos criar dois funções simples so pra teste, vamos criar a primeira MessagemADM que só deverar ser executada por usuario admistrador. E para isto vamos usar um decoração de tag no na função. Da seguinte forma.

_
Function MenssagemADM() As String
Return "adiministrador"
End Function

O que eu digo aqui e que a permisão sera dada por demanda aos usuarios que tiverem papel de administrador.

E agora vamos criar uma outra que será executada por todo usuario autenticado.

_
Function MenssagemUSE() As String
Return "Usuario"
End Function

Aqui tambem a permisão sera dada por demanda a todo usuario autenticado.

Agora sim no primeiro botão que chamaremos de btnAdm vamos escrever o seguinte codigo.

Sub BtnAdm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdm.Click
Try
MessageBox.Show(MenssagemADM)
Catch
MessageBox.Show("Negado")
End Try
End Sub

E no outro botão chamado btnUser faremos um codigo igual só que chamando a função MenssagemUSE

Private Sub btnUser_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUser.Click
Try
MessageBox.Show(MenssagemUSE)
Catch
MessageBox.Show("Negado")
End Try
End Sub


Percebeu ?, com este codigo joão que e adminstrador pode executar os dois metodos, mas maria não só pode executar o de usuario por ser autenticada, e só atribuir as permissões aos usuarios e dizer aos metodos quem pode fazer o que, muito melhor do os milhares de codigos loucos que tem por ai com listas em tabelas de quem pode o que e a onde ou cases selects infinitos.Os cuidados aqui são apenas dois o primeiro deles e na tag de autenticação que e case sencitive e que a chamada dos metodos controlados sempre devem ser entre try/catch por que quando e feita a tentativa de acesso a um metodo que não e permidido e lancado um erro. Valeu pessoal e até a proxima.