Habilitar a geração de código QR em aplicativos autenticadores TOTP em um aplicativo Web Blazor do ASP.NET Core
Este artigo explica como configurar um aplicativo Web Blazor do ASP.NET Core com a geração de código QR em aplicativos autenticadores TOTP.
Para ver uma introdução à 2FA (autenticação de dois fatores) com aplicativos autenticadores usando um algoritmo de TOTP (Senhas Avulsas por Tempo Limitado), confira Habilitar a geração de código QR em aplicativos autenticadores TOTP no ASP.NET Core.
Aviso
Um código TOTP do ASP.NET Core deve ser mantido em segredo porque pode ser usado para autenticar com sucesso várias vezes antes de expirar.
Gerar o componente Habilitar Autenticador por scaffolding no aplicativo
Siga as diretrizes descritas em Gerar o Identity por scaffolding em projetos do ASP.NET Core para gerar Pages\Manage\EnableAuthenticator
por scaffolding no aplicativo.
Observação
Embora apenas o componente EnableAuthenticator
esteja selecionado para scaffolding neste exemplo, no momento, o scaffolding adiciona todos os componentes Identity ao aplicativo. Além disso, exceções podem ser geradas durante o processo de scaffolding no aplicativo. Se ocorrerem exceções quando ocorrerem migrações de banco de dados, interrompa o aplicativo e reinicie o aplicativo em cada exceção. Para obter mais informações, confira Exceções de scaffolding para um aplicativo Web Blazor (dotnet/Scaffolding
nº 2694).
Tenha paciência enquanto as migrações são executadas. Dependendo da velocidade do sistema, as migrações de banco de dados podem demorar alguns minutos para serem concluídas.
Para obter mais informações, veja Scaffold Identity em projetos ASP.NET Core. Para obter orientação sobre como usar a CLI do .NET em vez do Visual Studio, veja Ferramenta geradora de código ASP.NET Core (`aspnet-codegenerator`).
Adicionando códigos QR à página de configuração 2FA
Essas instruções usam o qrcode.js: gerador de QRCode entre navegadores para JavaScript de Shim Sangmin (repositório GitHub davidshimjs/qrcodejs
).
Baixe a biblioteca qrcode.min.js
para a pasta wwwroot
do projeto de servidor da solução. A biblioteca não tem nenhuma dependência.
No componente App
(Components/App.razor
), coloque uma referência de script de biblioteca após a Blazormarca de <script>
:
<script src="qrcode.min.js"></script>
O componente EnableAuthenticator
, que faz parte do sistema de código QR do aplicativo e exibe o código QR para os usuários, adota a SSR estática (renderização estática do lado do servidor) com a navegação aprimorada. Portanto, os scripts normais não podem ser executados quando o componente é carregado ou atualizado com a navegação aprimorada. São necessárias etapas extras para disparar o código QR a ser carregado na interface do usuário quando a página é carregada. Para fazer o carregamento do código QR, a abordagem explicada em JavaScript do Blazor no ASP.NET Core com a SSR estática (renderização estática do lado do servidor) é adotada.
Adicione o inicializador de JavaScript a seguir à pasta wwwroot
do projeto do servidor. O espaço reservado {NAME}
precisa ser o nome do assembly do aplicativo para que Blazor localize e carregue o arquivo automaticamente. Se o nome do assembly do aplicativo de servidor for BlazorSample
, o arquivo será nomeado como BlazorSample.lib.module.js
.
wwwroot/{NAME}.lib.module.js
:
const pageScriptInfoBySrc = new Map();
function registerPageScriptElement(src) {
if (!src) {
throw new Error('Must provide a non-empty value for the "src" attribute.');
}
let pageScriptInfo = pageScriptInfoBySrc.get(src);
if (pageScriptInfo) {
pageScriptInfo.referenceCount++;
} else {
pageScriptInfo = { referenceCount: 1, module: null };
pageScriptInfoBySrc.set(src, pageScriptInfo);
initializePageScriptModule(src, pageScriptInfo);
}
}
function unregisterPageScriptElement(src) {
if (!src) {
return;
}
const pageScriptInfo = pageScriptInfoBySrc.get(src);
if (!pageScriptInfo) {
return;
}
pageScriptInfo.referenceCount--;
}
async function initializePageScriptModule(src, pageScriptInfo) {
if (src.startsWith("./")) {
src = new URL(src.substr(2), document.baseURI).toString();
}
const module = await import(src);
if (pageScriptInfo.referenceCount <= 0) {
return;
}
pageScriptInfo.module = module;
module.onLoad?.();
module.onUpdate?.();
}
function onEnhancedLoad() {
for (const [src, { module, referenceCount }] of pageScriptInfoBySrc) {
if (referenceCount <= 0) {
module?.onDispose?.();
pageScriptInfoBySrc.delete(src);
}
}
for (const { module } of pageScriptInfoBySrc.values()) {
module?.onUpdate?.();
}
}
export function afterWebStarted(blazor) {
customElements.define('page-script', class extends HTMLElement {
static observedAttributes = ['src'];
attributeChangedCallback(name, oldValue, newValue) {
if (name !== 'src') {
return;
}
this.src = newValue;
unregisterPageScriptElement(oldValue);
registerPageScriptElement(newValue);
}
disconnectedCallback() {
unregisterPageScriptElement(this.src);
}
});
blazor.addEventListener('enhancedload', onEnhancedLoad);
}
Adicione o componente PageScript
compartilhado a seguir ao aplicativo de servidor.
Components/PageScript.razor
:
<page-script src="@Src"></page-script>
@code {
[Parameter]
[EditorRequired]
public string Src { get; set; } = default!;
}
Adicione o arquivo JS colocado ao componente EnableAuthenticator
, que está localizado em Components/Account/Pages/Manage/EnableAuthenticator.razor
. A função onLoad
cria o código QR com a biblioteca qrcode.js
de Sangmin usando o URI de código QR produzido pelo método GenerateQrCodeUri
no bloco @code
do componente.
Components/Account/Pages/Manage/EnableAuthenticator.razor.js
:
export function onLoad() {
const uri = document.getElementById('qrCodeData').getAttribute('data-url');
new QRCode(document.getElementById('qrCode'), uri);
}
No componente <PageTitle>
do componente EnableAuthenticator
, adicione o componente PageScript
com o caminho para o arquivo JS colocado:
<PageScript Src="./Components/Account/Pages/Manage/EnableAuthenticator.razor.js" />
Observação
Uma alternativa ao uso da abordagem com o componente PageScript
é usar um ouvinte de eventos (blazor.addEventListener("enhancedload", {CALLBACK})
) registrado em um inicializador afterWebStarted
JSpara escutar as atualizações de página causadas pela navegação aprimorada. O retorno de chamada (espaço reservado {CALLBACK}
) executa a lógica de inicialização do código QR.
Usando a abordagem de retorno de chamada com enhancedload
, o código é executado para cada navegação aprimorada, mesmo quando o <div>
do código QR não é renderizado. Portanto, um código adicional deve ser adicionado para verificar a presença do <div>
antes da execução do código que adiciona um código QR.
Exclua o elemento <div>
que contém as instruções do código QR:
- <div class="alert alert-info">
- Learn how to <a href="https://go.microsoft.com/fwlink/?Linkid=852423">enable
- QR code generation</a>.
- </div>
Localize os dois elementos <div>
em que o código QR deve aparecer e o local em que os dados do código QR são armazenados na página.
Faça as seguintes alterações:
- Para o
<div>
vazio, dê ao elemento umaid
igual aqrCode
. - Para o
<div>
com o atributodata-url
, dê ao elemento umaid
deqrCodeData
.
- <div></div>
- <div data-url="@authenticatorUri"></div>
+ <div id="qrCode"></div>
+ <div id="qrCodeData" data-url="@authenticatorUri"></div>
Altere o nome do site no método GenerateQrCodeUri
do componente EnableAuthenticator
. O valor padrão é Microsoft.AspNetCore.Identity.UI
. Altere o valor para um nome de site significativo que os usuários possam identificar com facilidade no aplicativo autenticador, juntamente com outros códigos QR para outros aplicativos. Mantenha o valor codificado por URL. Os desenvolvedores costumam definir um nome de site que corresponde ao nome da empresa. Exemplos: Yahoo, Amazon, Etsy, Microsoft, Zoho.
No exemplo a seguir, o espaço reservado {SITE NAME}
é o local do nome do site (empresa):
private string GenerateQrCodeUri(string email, string unformattedKey)
{
return string.Format(
CultureInfo.InvariantCulture,
AuthenticatorUriFormat,
- UrlEncoder.Encode("Microsoft.AspNetCore.Identity.UI"),
+ UrlEncoder.Encode("{SITE NAME}"),
UrlEncoder.Encode(email),
unformattedKey);
}
Execute o aplicativo e verifique se o código QR é digitalizável e se o código é validado.
Aviso
Um código TOTP do ASP.NET Core deve ser mantido em segredo porque pode ser usado para autenticar com sucesso várias vezes antes de expirar.
Componente EnableAuthenticator
na fonte de referência
O componente EnableAuthenticator
pode ser inspecionado na fonte de referência:
Componente EnableAuthenticator
na fonte de referência
Observação
Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).