Autor: Willmove && Heath Stewart
Página inicial: http://www.amuhouse.com
E-mail: [email protected]
Observação: acabei de aprender ASP.NET há dois meses e vi um artigo intitulado Segurança baseada em função com autenticação de formulários em codeproject.com e achei muito útil. Naquela época eu queria traduzi-lo para o chinês. No entanto, a tradução direta é realmente chata. Nos últimos dois dias, referi-me a este artigo de Heath Stewart e, com base no meu próprio entendimento, escrevi-o em chinês de acordo com as minhas próprias ideias e expressões. Em anexo está um aplicativo da web de demonstração que fiz para este artigo.
Se houver algum mal-entendido, escreva para apontar ou deixe um comentário.
P.S. Spam é realmente irritante, por favor, mostre seu respeito.
O artigo original está em http://www.codeproject.com/aspnet/formsroleauth.asp
Autor originalHeath Stewart
resumo:
O ASP.NET fornece um mecanismo de autenticação baseado em funções, mas seu suporte a funções é incompleto. Este artigo tenta ilustrar como implementar e usar este mecanismo de autenticação baseado em funções através de alguns exemplos.
Introdução:
A autenticação de formulário no ASP.NET é um recurso muito poderoso que requer apenas uma pequena quantidade de código para implementar um sistema simples de autenticação de segurança independente de plataforma.
No entanto, se você precisar de um mecanismo de autenticação mais complexo e eficiente, precisará aproveitar sua flexibilidade dividindo muitos usuários em grupos de usuários. A Autenticação Integrada do Windows fornece esse mecanismo de autenticação, mas usa NTLM, o Windows NT LAN Manager, portanto, não é multiplataforma. Agora, mais e mais pessoas estão usando sistemas Linux e há cada vez mais usuários do navegador Mozilla Forefox. Certamente não podemos manter essas pessoas de fora, por isso estamos procurando outro mecanismo de autenticação. Existem duas opções: uma é dividir o site em múltiplas áreas e fornecer múltiplas páginas de login, forçando os usuários a se cadastrarem e fazer login um por um, a outra é agrupar usuários e restringir os direitos de acesso de grupos de usuários específicos a uma determinada página; ou área. Esta última é certamente a melhor escolha. Podemos alcançar essa funcionalidade atribuindo funções a usuários individuais.
A Microsoft deixou o mecanismo de autenticação baseado em funções na autenticação de formulários para a plataforma .NET, mas temos que implementá-lo nós mesmos. Este artigo se esforça para cobrir alguns aspectos básicos sobre o mecanismo de autenticação baseada em funções na autenticação de formulários, como seu conceito, sua implementação, como aplicá-lo em aplicações web, etc.
Preparação necessária:
Primeiro precisamos criar um banco de dados, um projeto de aplicação Web, vários diretórios confidenciais com diferentes níveis de segurança e diversas páginas ASP.NET. Claro que você também pode adicioná-los ao seu projeto de aplicação web existente.
1. Para criar um banco de dados,
você deve primeiro escolher o sistema de gerenciamento de banco de dados SGBD que deseja usar. Este artigo usa o SQL Server 2000.
No banco de dados de projetos de aplicativos reais, geralmente há uma tabela de dados do usuário Usuários, que pode incluir a tag exclusiva do usuário: UserID, nome de usuário: Nome de usuário, senha: Senha, endereço de e-mail do usuário: E-mail, cidade do usuário: Cidade e o número de logins de usuários LoginCount etc. Você pode atribuir funções aos usuários criando uma tabela de dados UserInRoles (geralmente incluindo dois campos, nome de usuário: UserName, função de usuário: UserRoles).
Para simplificar, crio apenas uma tabela de dados de Usuários, que possui 3 campos, nome de usuário UserName, senha Senha e funções de usuário UserRoles. Antes de criar uma tabela, você precisa selecionar um banco de dados ou criar um novo banco de dados. Para criar um novo banco de dados denominado WebSolution, é necessária apenas uma instrução SQL simples:
código do programa
Criar BANCO DE DADOS WebSolução
Para selecionar um banco de dados chamado msdb
em GO
, você pode usar a instrução SQL:
código do programa
USAR msdb
IR
A seguir, criamos a tabela de dados Users que acabamos de mencionar. O script SQL é o seguinte:
Código do programa
Create TABLE Users.
(
Nome de usuário nvarchar(100) CONSTRAINT PK_UserName CHAVE PRIMÁRIA,
Senha nvarchar(150),
Funções do usuário nvarchar(100)
)
pode criar credenciais de índice para esta tabela A instrução SQL é a seguinte:
Código do programa
Criar credenciais INDEX ON Users.
(
Nome de usuário,
Senha
)
A criação de um índice é opcional e depende de você. Consulte as informações relevantes sobre os benefícios e desvantagens da indexação.
Em seguida, adicionamos dados a este banco de dados de usuários. O nome do personagem é de sua escolha, mas é melhor usar um nome significativo, como
"Administrador" (administrador de nível superior), "Gerente" (administrador), "Membro" (membro associado), "Usuário" (usuário comum), etc. Por exemplo:
Nome de usuário|Senha|Funções
"willmove"|"pwd123"|"Administrador,Usuário"
"amuhouse"|"pwd123"|"User"
é:
código do programa
--observe que '45CB41B32DCFB917CCD8614F1536D6DA' é uma string criptografada por md5 usando 'pwd123'
Insira INTO usuários (nome de usuário, senha, funções de usuário) VALORES ('willmove', '45CB41B32DCFB917CCD8614F1536D6DA', 'Administrador, usuário')
IR
Insira INTO usuários (nome de usuário, senha, funções de usuário) VALORES ('amuhouse','45CB41B32DCFB917CCD8614F1536D6DA','Usuário')
IR
Observe que as funções diferenciam maiúsculas de minúsculas porque diferenciam maiúsculas de minúsculas no arquivo Web.config. Agora criamos várias páginas necessárias para implementar este mecanismo de autenticação de segurança.
A primeira é a página de login do usuário Login.aspx
Se você ainda não criou um aplicativo Web, crie um agora. Claro que você também pode criar esta página em uma aplicação web existente. Aqui presumo que um aplicativo Web chamado RolebasedAuth foi criado (ou seja, Projeto no Visual Studio .Net). Coloquei este Login.aspx em seu diretório raiz, que pode ser acessado através de http://localhost/RolebasedAuth/Login.aspx .
Não importa onde este Login.aspx esteja colocado, mas ele deve estar acessível ao público.
No caminho raiz do aplicativo, criamos dois subdiretórios secretos, nomeadamente Admin e User.
A seguir, criamos um sistema de login de autenticação de formulários que suporta autenticação de função. Como a Microsoft não fornece um mecanismo de implementação simples, precisamos gastar algum tempo criando nós mesmos o tíquete de autenticação. Ele precisa armazenar uma pequena quantidade de informações É claro que alguns nomes devem ser iguais aos configurados no Web.config, caso contrário o ASP.NET pensará que seu ticket de autenticação é inválido e forçará você a redirecionar para a página de login. Adicionamos dois controles TextBox a Login.aspx no VS.NET e os nomeamos UserNameTextBox e PasswordTextBox. Também adicionamos um Button e o nomeamos LoginButton. Adicione o código necessário no método LoginButton_Click. do seguinte modo:
código do programa
private void LoginButton_Click (objeto remetente, System.EventArgs e)
{
// Inicializa a autenticação do Forms
// Observe que está no namespace System.Web.Security
// Então adicione using System.Web.Security no início do código;
FormsAuthentication.Initialize();
// Cria objetos de comando de conexão e operação de banco de dados
// Observe que ele está no namespace System.Data.SqlClient
// Então adicione using System.Data.SqlClient no início do código;
Conexão SqlConnection =
new SqlConnection("Fonte de dados=sun-willmove;segurança integrada=SSPI;Catálogo inicial=WebSolution;");
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "Selecione UserRoles FROM Usuários Onde UserName=@username " +
"E Senha=@senha ";
//Preenche cada parâmetro
cmd.Parameters.Add("@nomedeusuário", SqlDbType.NVarChar, 100).Value =
UserNameTextBox.Text;
cmd.Parameters.Add("@senha", SqlDbType.NVarChar, 150).Value =
FormsAuthentication.HashPasswordForStoringInConfigFile(
PasswordTextBox.Text, "md5"); // ou "sha1"
// Executa comando de operação do banco de dados
conexão.Open();
Leitor SqlDataReader = cmd.ExecuteReader();
if (leitor.Leitura())
{
// Para implementar a autenticação, crie um novo ticket
Tíquete FormsAuthenticationTicket = novo FormsAuthenticationTicket(
1, // Número da versão do ticket
UserNameTextBox.Text, // Titular do ingresso
DateTime.Now, //Hora para alocar tickets
DateTime.Now.AddMinutes(30), //Tempo de expiração
true, //requer cookie do usuário
reader.GetString(0), // Dados do usuário, aqui está a função do usuário
FormsAuthentication.FormsCookiePath);//Caminho válido do cookie
//Use a chave de máquina do código de máquina para criptografar cookies para transmissão segura
string hash = FormsAuthentication.Encrypt(ticket);
Cookie HttpCookie = novo HttpCookie(
FormsAuthentication.FormsCookieName, // O nome do cookie de autenticação
hash); //Cookie criptografado
//Define o tempo de expiração do cookie para ser consistente com o tempo de expiração dos tickets
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
//Adicionar cookies à resposta da solicitação da página;
Response.Cookies.Add(cookie);
//Redirecionar o usuário para a página solicitada anteriormente,
// Se nenhuma página foi solicitada antes, redireciona para a página inicial
string returnUrl = Request.QueryString["ReturnUrl"];
if (returnUrl == null) returnUrl = "./";
// Não chame o método FormsAuthentication.RedirectFromLoginPage.
// Porque substituirá o ticket (cookie) recém adicionado
Response.Redirect(returnUrl);
}
outro
{
// Não diga ao usuário "A senha está errada", isso equivale a dar uma chance ao intruso.
// Porque eles sabem que o nome de usuário digitado existe
//
ErrorLabel.Text = "Nome de usuário ou senha estão errados, tente novamente!";
ErrorLabel.Visible = verdadeiro;
}
leitor.Fechar();
conexão.Fechar();
}
O código da página aspx do front-end é o seguinte:
código do programa
<%@ Page language="c#" Codebehind="Login.aspx.cs" AutoEventWireup="false" Inherits="RolebasedAuth.Login" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<CABEÇA>
<título>Login</título>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content=" http://schemas.microsoft.com/intellisense/ie5 ">
</HEAD>
<corpo>
<form id="Form1" method="post" runat="servidor">
<P>
<asp:Label id="Label1" runat="server">Nome de usuário:</asp:Label>
<asp:TextBox id="UserNameTextBox" runat="server"></asp:TextBox></P>
<P><FONT face="宋体"> </FONT>
<asp:Label id="Label2" runat="server">Senha:</asp:Label>
<asp:TextBox id="PasswordTextBox" runat="server" TextMode="Password"></asp:TextBox></P>
<P>
<asp:Label id="ErrorLabel" runat="server" Visible="False"></asp:Label></P>
<P>
<asp:Button id="LoginButton" runat="server" Text="Login"></asp:Button></P>
</form>
</body>
</HTML>
Você notará o que fizemos com a senha acima: hash. A criptografia hash é um algoritmo unidirecional (irreversível) que gera uma matriz única de caracteres. Portanto, alterar a caixa de até mesmo uma letra na senha produzirá uma coluna de hash completamente diferente. Armazenamos essas senhas criptografadas no banco de dados, que é mais seguro. Em uma aplicação prática, você pode querer recuperar uma senha esquecida de um usuário. Mas o hash é irreversível, então você não conseguirá recuperar a senha original. Mas você pode alterar a senha do usuário e informar a ele a senha alterada. Se um site pode fornecer senhas antigas, você precisa pensar com clareza: seus dados de usuário não estão seguros! Na verdade, a maioria dos sites domésticos armazena diretamente as senhas dos usuários no banco de dados, sem criptografia. Se um hacker tiver sucesso, essas contas de usuário estarão em perigo!
Sem SSL, sua senha é transmitida em texto não criptografado pela rede. Pode ser roubado durante a transmissão. Criptografar senhas no lado do servidor apenas garante a segurança do armazenamento de senhas. Informações relacionadas ao SSL podem ser encontradas em http://www.versign.com ou http://www.thewte.com .
Se não quiser armazenar a senha criptografada no banco de dados, você pode alterar o código acima para
FormsAuthentication.HashPasswordForStoringInConfigFile(PasswordTextBox.Text, "md5") pode ser alterado para PasswordTextBox.Text.
A seguir, precisamos modificar o arquivo Global.asax. Se a sua aplicação web não tiver este arquivo, clique com o botão direito no projeto da aplicação web e selecione "Adicionar->Adicionar Novo Item...->Classe de Aplicação Global". Em Global.asax ou Global.asax.cs, encontre o método (função) chamado Application_AuthenticationRequest. Primeiro confirme se os namespaces System.Security.Principal e System.Web.Security foram incluídos ou usados e, em seguida, modifique o código modificado:
código do programa
void protegido Application_AuthenticateRequest (remetente do objeto, EventArgs e)
{
if (HttpContext.Current.User! = Nulo)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity é FormsIdentity)
{
FormuláriosIdentidade id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
// Obtém os dados do usuário armazenados no ticket, que na verdade é a função do usuário aqui
string userData = ticket.UserData;
string[] papéis = userData.Split(',');
HttpContext.Current.User = novo GenericPrincipal(id, funções);
}
}
}
}
O ticket de autenticação (nome de usuário e senha) não é armazenado como parte do cookie e não pode ser, pois os usuários podem modificar seus cookies.
Na verdade, FormsAuthentication usa a chave da sua máquina (geralmente em machine.config) para criptografar o ticket (FormsAuthenticationTicket). Usamos UserData para armazenar funções de usuário e gerar novas credenciais. Depois que a credencial for criada, ela será adicionada ao contexto atual (ou seja, HttpContext) para que possa ser usada para recuperar a função do usuário.
Em seguida, configuramos o diretório secreto (ou seja, o "diretório de segurança", um diretório que apenas usuários específicos, como administradores, têm permissão para acessar). Primeiro verifique se existe um arquivo Web.config no diretório raiz do seu aplicativo web. Você também pode criar um arquivo Web.config em seu subdiretório. É claro que esse arquivo Web.config é restrito (alguns parâmetros não podem ser definidos).
Para implementar a autenticação de segurança, encontreo código do programa
no nó <system.web> no arquivo Web.config no diretório raiz do aplicativo Web.
<authentication mode="Windows" />, altere para
<authentication mode="Forms">
<nome do formulário = "AMUHOUSE.ASPXAUTH"
loginUrl="Login.aspx"
proteção = "Todos"
caminho="./" />
</autenticação>
<autorização>
<permitir usuários="*"/>
</authorization>
No nome="AMUHOUSE.ASPXAUTH" acima, o nome AMUHOUSE.ASPXAUTH é arbitrário. Para controlar as permissões de usuários ou grupos de usuários, podemos ter dois métodos. Um é configurar o arquivo Web.config no diretório raiz do aplicativo e o outro é criar um arquivo Web.config independente no diretório secreto. (O último pode ser melhor.) Se for o primeiro, o Web.config deverá conter o seguinte conteúdo (ou conteúdo semelhante):
código do programa
<configuração>
<sistema.web>
<modo de autenticação="Formulários">
<nome do formulário = "AMUHOUSE.ASPXAUTH"
loginUrl="login.aspx"
proteção = "Todos"
caminho="/"/>
</autenticação>
<autorização>
<permitir usuários="*"/>
</autorização>
</system.web>
<caminho de localização="./Admin">
<sistema.web>
<autorização>
<!-- Atenção! A ordem e o caso das linhas a seguir são muito importantes! -->
<allow role="Administrador"/>
<negar usuários="*"/>
</autorização>
</system.web>
</local>
<caminho de localização="./Usuário">
<sistema.web>
<autorização>
<!-- Atenção! A ordem e o caso das linhas a seguir são muito importantes! -->
<allow role="Usuário"/>
<negar usuários="*"/>
</autorização>
</system.web>
</local>
</configuração>
Para tornar os diretórios dos aplicativos da web não dependentes uns dos outros e facilitar sua renomeação ou movimentação, você pode optar por configurar um arquivo Web.config separado em cada subdiretório de segurança. Basta configurar o nó <authorization/> da seguinte forma:
código do programa
<configuração>
<sistema.web>
<autorização>
<!-- Atenção! A ordem e o caso das linhas a seguir são muito importantes! -->
<allow role="Administrador"/>
<negar usuários="*"/>
</autorização>
</system.web>
</configuração>
Deve ser lembrado novamente que as funções acima diferenciam maiúsculas de minúsculas. Por conveniência, você também pode modificar o acima para:
<allow role="Administrador,administrador" />
Se quiser permitir ou negar o acesso de múltiplas funções a este diretório, você pode separá-las com vírgulas, como:
<allow Roles="Administrador,Membro,Usuário" />
<deny users="*" />
Neste ponto, configuramos um mecanismo de autenticação de segurança baseado em função para o site. Você pode compilar seu programa primeiro e depois tentar acessar um diretório secreto, como http://localhost/RolebasedAuth/Admin , momento em que você será redirecionado para a página de login do usuário. Se você efetuar login com êxito e sua função tiver direitos de acesso a esse diretório, você retornará a ele. Pode haver usuários (ou intrusos) tentando entrar no diretório confidencial. Podemos usar uma Sessão para armazenar o número de vezes que o usuário efetuou login. Se o número exceder um determinado número, o usuário não terá permissão para efetuar login. e "O sistema rejeitou sua solicitação de login!"
Abaixo, discutimos como fazer com que os controles da web exibam conteúdos diferentes com base nas funções do usuário.
Às vezes é melhor exibir o conteúdo com base na função do usuário, porque você provavelmente não deseja criar um monte de páginas com muito conteúdo duplicado para tantas funções diferentes (grupos de usuários). Nesse site, várias contas de usuário podem coexistir e contas de usuários pagas podem acessar conteúdo pago adicional. Outro exemplo é uma página que exibirá um botão "Enter Admin" com link para a página Admin se o usuário atual estiver na função de "Administrador". Implementaremos esta página agora.
A classe GenericPrincipal que usamos acima implementa a interface IPincipal. Esta interface possui um método chamado IsInRole() e seu parâmetro é uma string. Se quisermos exibir conteúdo para usuários logados cuja função é "Administrador", podemos adicionar o seguinte código em Page_Load:
Código do programa
if (User.IsInRole("Administrador"))
AdminLink.Visible = true;
O código inteiro da página é o seguinte (para simplificar, o código de fundo também é escrito na página aspx):
código do programa
<html>
<cabeça>
<título>Bem-vindo! </título>
<script runat="servidor">
protegido void Page_Load (remetente do objeto, EventArgs e)
{
if (User.IsInRole("Administrador"))
AdminLink.Visible = verdadeiro;
outro
AdminLink.Visible = falso;
}
</script>
</head>
<corpo>
<h2>Bem-vindo! </h2>
<p>Bem-vindo à Amu House http://amuhouse.com/ ^_^</p>
<asp:HyperLink id="AdminLink" runat="servidor"
Text="Página inicial do administrador" NavigateUrl="./Admin"/>
</body>
</html>
Desta forma, o controle HyperLink vinculado ao diretório Admin só será exibido para usuários cuja função seja Administrador. Você também pode fornecer aos usuários não conectados um link para a página de login, como:
código do programa
protegido void Page_Load (remetente do objeto, System.EventArgs e)
{
if (User.IsInRole("Administrador"))
{
AdminLink.Text = "Administrador, entre";
AdminLink.NavigateUrl="./Admin";
}
senão if(User.IsInRole("Usuário"))
{
AdminLink.Text = "Usuários registrados por favor insiram";
AdminLink.NavigateUrl="./Usuário"
;
outro
{
AdminLink.Text = "Por favor faça login";
AdminLink.NavigateUrl="Login.aspx?ReturnUrl=" + Request.Path;
}
}
Aqui, definindo a variável QueryString chamada ReturnUrl, podemos retornar o usuário à página atual após o login bem-sucedido.
resumo:
Este artigo é usado para ajudá-lo a compreender a importância e a praticidade dos mecanismos de segurança baseados em funções e também usa o ASP.NET para implementar mecanismos de segurança baseados em funções. Não é um mecanismo difícil de implementar, mas pode exigir algum conhecimento sobre o que são credenciais de usuário, como autenticar usuários e como autenticar usuários autorizados. Ficarei muito feliz se você achar útil. Espero que ele possa orientá-lo na implementação da autenticação de segurança de formulários baseada em funções em seu site.
Apegado:
Exemplo de código-fonte do projeto para este artigo: