Migrar da autenticação de Associação do ASP.NET para a Identity do ASP.NET Core 2.0
Por Isaac Levin
Este artigo demonstra como migrar o esquema de banco de dados para aplicativos ASP.NET usando a autenticação de Associação para a Identity do ASP.NET Core 2.0.
Observação
Este documento fornece as etapas necessárias para migrar o esquema de banco de dados para aplicativos baseados em Associação do ASP.NET para o esquema de banco de dados usado para a Identity do ASP.NET Core. Para obter mais informações sobre como migrar da autenticação baseada em Associação do ASP.NET para a Identity do ASP.NET, consulte Migrar um aplicativo existente da Associação do SQL para a Identity do ASP.NET. Para obter mais informações sobre a Identity do ASP.NET Core, confira Introdução à Identity no ASP.NET Core.
Revisão do esquema de Associação
Antes do ASP.NET 2.0, os desenvolvedores eram encarregados de criar todo o processo de autenticação e autorização para seus aplicativos. Com o ASP.NET 2.0, a Associação foi introduzida, fornecendo uma solução clichê para lidar com a segurança dentro de aplicativos ASP.NET. Os desenvolvedores puderam então inicializar um esquema em um banco de dados do SQL Server com a Ferramenta de Registro do SQL Server no ASP.NET (Aspnet_regsql.exe
) (não há mais suporte). Depois de executar esse comando, as tabelas a seguir foram criadas no banco de dados.
Para migrar aplicativos existentes para a Identity do ASP.NET Core 2.0, os dados nessas tabelas precisam ser migrados para as tabelas usadas pelo novo esquema de Identity.
Esquema de Identity do ASP.NET Core 2.0
O ASP.NET Core 2.0 segue o princípio Identity introduzido no ASP.NET 4.5. Embora o princípio seja compartilhado, a implementação entre as estruturas é diferente, mesmo entre versões do ASP.NET Core (consulte Migrar autenticação e Identity para o ASP.NET Core 2.0).
A maneira mais rápida de exibir o esquema para a Identity do ASP.NET Core 2.0 é criar um novo aplicativo ASP.NET Core 2.0. Siga estas etapas no Visual Studio 2017:
Selecione Arquivo>Novo>Projeto.
Crie um novo projeto do Aplicativo Web ASP.NET Core nomeado CoreIdentitySample.
Selecione ASP.NET Core 2.0 na lista suspensa e, em seguida, selecione Aplicativo Web. Esse modelo produz um aplicativo PáginasRazor . Antes de clicar em OK, clique em Alterar Autenticação.
Escolha Contas de Usuário Individuais para os modelos de Identity. Por fim, clique em OK e, em seguida, em OK. O Visual Studio cria um projeto usando o modelo de Identity do ASP.NET Core.
Selecione Ferramentas>Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes para abrir o PMC (Console do Gerenciador de Pacotes) na janela.
Navegue até a raiz do projeto no PMC e execute o comando Entity Framework Core
Update-Database
.A Identity do ASP.NET Core 2.0 usa o EF Core para interagir com o banco de dados que armazena os dados de autenticação. Para que o aplicativo recém-criado funcione, é necessário que haja um banco de dados para armazenar esses dados. Depois de criar um novo aplicativo, a maneira mais rápida de inspecionar o esquema em um ambiente de banco de dados é criar o banco de dados usando EF Core Migrações. Esse processo cria um banco de dados, localmente ou em outro lugar, que imita esse esquema. Revise a documentação anterior para obter mais informações.
Os comandos do EF Core usam a cadeia de conexão para o banco de dados especificado em
appsettings.json
. A cadeia de conexão a seguir tem como destino um banco de dados no localhost chamado asp-net-core-identity. Nessa configuração, o EF Core é configurado para usar a cadeia de conexãoDefaultConnection
.{ "ConnectionStrings": { "DefaultConnection": "Server=localhost;Database=aspnet-core-identity;Trusted_Connection=True;MultipleActiveResultSets=true" } }
Aviso
Este artigo mostra o uso de cadeias de conexão. Com um banco de dados local, o usuário não precisa ser autenticado, mas na produção, as cadeias de conexão às vezes incluem uma senha para autenticação. Uma credencial de senha do proprietário do recurso (ROPC) é um risco de segurança que deve ser evitado em bancos de dados de produção. Os aplicativos de produção devem usar o fluxo de autenticação mais seguro disponível. Para obter mais informações sobre autenticação para aplicativos implantados em ambientes de teste ou produção, consulte Fluxos de autenticação seguros.
Selecione Exibir>Pesquisador de Objetos do SQL Server. Expanda o nó correspondente ao nome do banco de dados especificado na propriedade
ConnectionStrings:DefaultConnection
deappsettings.json
.O comando
Update-Database
criou o banco de dados especificado com o esquema e todos os dados necessários para a inicialização do aplicativo. A imagem a seguir ilustra a estrutura da tabela criada com as etapas anteriores.
Migrar o esquema
Há diferenças sutis nas estruturas de tabela e nos campos para Associação e para a Identity do ASP.NET Core. O padrão mudou substancialmente para autenticação/autorização com aplicativos ASP.NET e ASP.NET Core. Os principais objetos que ainda são usados com a Identity são Usuários e Funções. Aqui estão as tabelas de mapeamento para Usuários, Funções e UserRoles.
Usuários
Identity Coluna ( dbo.AspNetUsers ) |
Type | Associação Coluna ( dbo.aspnet_Users / dbo.aspnet_Membership ) |
Type |
---|---|---|---|
Id |
string |
aspnet_Users.UserId |
string |
UserName |
string |
aspnet_Users.UserName |
string |
Email |
string |
aspnet_Membership.Email |
string |
NormalizedUserName |
string |
aspnet_Users.LoweredUserName |
string |
NormalizedEmail |
string |
aspnet_Membership.LoweredEmail |
string |
PhoneNumber |
string |
aspnet_Users.MobileAlias |
string |
LockoutEnabled |
bit |
aspnet_Membership.IsLockedOut |
bit |
IsLockedOut
não é mapeado para LockoutEnabled
. IsLockedOut
será definido se um usuário tiver muitos logons com falha e estiver bloqueado por um tempo definido. LockoutEnabled
permite bloquear um usuário com muitas tentativas de entrada com falha. Quando o usuário tiver muitas tentativas de entrada com falha, LockoutEnd
será definido como uma data no futuro e o usuário não poderá entrar até essa data. Se LockoutEnabled
for false, um usuário nunca será bloqueado por muitas tentativas de entrada com falha. De acordo com o OWASP, o bloqueio de conta temporário após várias tentativas com falha é um alvo muito simples para ataques DoS contra usuários legítimos.
Para obter mais informações sobre bloqueio, consulte Teste do OWASP para Mecanismo de Bloqueio Fraco.
Os aplicativos que migram para a Identity que desejam habilitar o bloqueio de logon com falha devem definir LockoutEnabled
como true como parte da migração.
Observação
Nem todos os mapeamentos de campo se assemelham a relações um-para-um de Associação para a Identity do ASP.NET Core. A tabela anterior usa o esquema de Usuário Associado padrão e mapeia-o para o esquema de Identity do ASP.NET Core. Todos os outros campos personalizados que foram usados para Associação precisam ser mapeados manualmente. Neste mapeamento, não há nenhum mapa para senhas, pois os critérios e sais de senha não migram entre os dois. É recomendável deixar a senha como nula e pedir aos usuários que redefinam suas senhas. Na Identity do ASP.NET Core, LockoutEnd
deverá ser definido como alguma data no futuro se o usuário estiver bloqueado. Isso é mostrado no script de migração.
Funções
Identity Coluna ( dbo.AspNetRoles ) |
Type | Associação Coluna ( dbo.aspnet_Roles ) |
Type |
---|---|---|---|
Id |
string |
RoleId |
string |
Name |
string |
RoleName |
string |
NormalizedName |
string |
LoweredRoleName |
string |
Funções de usuário
Identity Coluna ( dbo.AspNetUserRoles ) |
Type | Associação Coluna ( dbo.aspnet_UsersInRoles ) |
Type |
---|---|---|---|
RoleId |
string |
RoleId |
string |
UserId |
string |
UserId |
string |
Referencie as tabelas de mapeamento anteriores ao criar um script de migração para Usuários e Funções. O exemplo a seguir pressupõe que você tenha dois bancos de dados em um servidor de banco de dados. Um banco de dados contém os dados e o esquema de Associação do ASP.NET existentes. O outro banco de dados CoreIdentitySample foi criado usando as etapas descritas anteriormente. Os comentários são incluídos em linha para obter mais detalhes.
-- THIS SCRIPT NEEDS TO RUN FROM THE CONTEXT OF THE MEMBERSHIP DB
BEGIN TRANSACTION MigrateUsersAndRoles
USE aspnetdb
-- INSERT USERS
INSERT INTO CoreIdentitySample.dbo.AspNetUsers
(Id,
UserName,
NormalizedUserName,
PasswordHash,
SecurityStamp,
EmailConfirmed,
PhoneNumber,
PhoneNumberConfirmed,
TwoFactorEnabled,
LockoutEnd,
LockoutEnabled,
AccessFailedCount,
Email,
NormalizedEmail)
SELECT aspnet_Users.UserId,
aspnet_Users.UserName,
-- The NormalizedUserName value is upper case in ASP.NET Core Identity
UPPER(aspnet_Users.UserName),
-- Creates an empty password since passwords don't map between the 2 schemas
'',
/*
The SecurityStamp token is used to verify the state of an account and
is subject to change at any time. It should be initialized as a new ID.
*/
NewID(),
/*
EmailConfirmed is set when a new user is created and confirmed via email.
Users must have this set during migration to reset passwords.
*/
1,
aspnet_Users.MobileAlias,
CASE
WHEN aspnet_Users.MobileAlias IS NULL THEN 0
ELSE 1
END,
-- 2FA likely wasn't setup in Membership for users, so setting as false.
0,
CASE
-- Setting lockout date to time in the future (1,000 years)
WHEN aspnet_Membership.IsLockedOut = 1 THEN Dateadd(year, 1000,
Sysutcdatetime())
ELSE NULL
END,
aspnet_Membership.IsLockedOut,
/*
AccessFailedAccount is used to track failed logins. This is stored in
Membership in multiple columns. Setting to 0 arbitrarily.
*/
0,
aspnet_Membership.Email,
-- The NormalizedEmail value is upper case in ASP.NET Core Identity
UPPER(aspnet_Membership.Email)
FROM aspnet_Users
LEFT OUTER JOIN aspnet_Membership
ON aspnet_Membership.ApplicationId =
aspnet_Users.ApplicationId
AND aspnet_Users.UserId = aspnet_Membership.UserId
LEFT OUTER JOIN CoreIdentitySample.dbo.AspNetUsers
ON aspnet_Membership.UserId = AspNetUsers.Id
WHERE AspNetUsers.Id IS NULL
-- INSERT ROLES
INSERT INTO CoreIdentitySample.dbo.AspNetRoles(Id, Name)
SELECT RoleId, RoleName
FROM aspnet_Roles;
-- INSERT USER ROLES
INSERT INTO CoreIdentitySample.dbo.AspNetUserRoles(UserId, RoleId)
SELECT UserId, RoleId
FROM aspnet_UsersInRoles;
IF @@ERROR <> 0
BEGIN
ROLLBACK TRANSACTION MigrateUsersAndRoles
RETURN
END
COMMIT TRANSACTION MigrateUsersAndRoles
Após a conclusão do script anterior, o aplicativo da Identity do ASP.NET Core criado anteriormente é preenchido com Usuários associados. Os usuários precisam alterar suas senhas antes de fazer logon.
Observação
Se o sistema de Associação tiver usuários com nomes de usuário que não correspondem ao endereço de email, as alterações serão necessárias para o aplicativo criado anteriormente para acomodar isso. O modelo padrão espera que UserName
e Email
sejam os mesmos. Para situações em que são diferentes, o processo de logon precisa ser modificado para usar UserName
em vez de Email
.
No PageModel
da Página de Logon, localizada em , remova o atributo [EmailAddress]
da propriedade Email. Renomeie-o como UserName. Isso requer uma alteração onde quer que o EmailAddress
seja mencionado, no Modo de Exibição e PageModel. O resultado se parece com o seguinte:
Próximas etapas
Neste tutorial, você aprendeu a portar usuários da associação do SQL para a Identity do ASP.NET Core 2.0. Para obter mais informações sobre a Identity do ASP.NET Core, consulte Introdução à Identity.