Crie um mecanismo de login usando autenticação de cookie e crie um mecanismo a ser redirecionado se você não estiver autenticado

Página atualizada :
Data de criação de página :

Ambiente operacional

Estúdio Visual
  • Comunidade do Visual Studio 2022
ASP.NET Core (MVC, Páginas Razor)
6.0

Inicialmente

Desta vez, o ASP.NET Core usará a autenticação de cookies como um mecanismo de autenticação de login. Você pode pensar na autenticação de cookies como sendo semelhante à autenticação de formulários tradicionais.

Outro mecanismo de autenticação para ASP.NET Core é ASP.NET Core Identity. Além da autenticação usando formulários, isso permite que você se autentique com APIs, use serviços de login externos, gerencie e redefina senhas, etc. Você pode usar muitos recursos. No entanto, do ponto de vista de apenas criar uma tela de login simples desta vez, será um mecanismo de autenticação um tanto exagerado. Não vamos usá-lo desta vez.

Nas dicas de autenticação de cookies introduzidas desta vez, você não pode exibir nada além da tela de login, a menos que você faça login. Se você tentar navegar para outra tela, você será redirecionado para a tela de login. Se você fizer login, poderá visualizar outras telas.

Por enquanto, você pode fazer login digitando seu nome de usuário e senha na tela de login. A própria autenticação do usuário é implementada como um local temporário. Neste caso, o foco principal está na implementação da autenticação de cookies, portanto, a essência do processo de determinação, como se a senha está correta, não é a essência.

Esta dica descreve apenas uma parte do programa. Para o código completo, baixe o programa completo. Ele também abrange as estruturas MVC e Razor Pages.

Criar um projeto

Inicie o Visual Studio e crie um novo projeto.

Para Razor Pages, selecione ASP.NET Core Web App ou, para MVC, selecione ASP.NET Core Web App (Model-View-Controller).

Especifique um nome de projeto de sua escolha e um local para o projeto.

Para o tipo de autenticação, selecione "Nenhum". Se você escolher outra autenticação, usará ASP.NET Identidade Principal. Quando terminar as configurações, clique no botão "Criar".

Após a criação do projeto, a tela mostrada abaixo será exibida quando a depuração for executada. Vamos criar um programa baseado nesta tela.

Editar Programa.cs (Razor Pages, MVC Common)

Adicione as definições necessárias para autenticação de cookie ao Program.cs. Os namespaces a serem adicionados são os seguintes:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

Aqui está builder.Services o código a ser adicionado ao .

// === 省略 ===

// 「Razor Pages」のコード
// builder.Services.AddRazorPages();
// 「MVC」のコード
// builder.Services.AddControllersWithViews();

// ※ここから追加

// Cookie による認証スキームを追加する
builder.Services
  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie();

builder.Services.AddAuthorization(options =>
{
  // AllowAnonymous 属性が指定されていないすべての画面、アクションなどに対してユーザー認証が必要となる
  options.FallbackPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();
});

// ※ここまで追加

var app = builder.Build();

// === 省略 ===

AddAuthenticationAddCookie Você pode habilitar a autenticação de cookies executando o método e. Se você não precisar alterar o nome do esquema, CookieAuthenticationDefaults.AuthenticationScheme especifique .

AddAuthorization Se você options.FallbackPolicy RequireAuthenticatedUser especificar para o método Você pode aplicar uma política de autenticação necessária a todas as páginas, todos os controladores e ações. Se você quiser exigir autenticação para qualquer coisa que não seja a tela de login, é um método útil em termos de reduzir o código e evitar erros na descrição. Você terá que escrever código que não requer autenticação para a tela de login separadamente.

A seguir está app o código para .

// === 省略 ===

app.UseRouting();

app.UseAuthentication(); // [追加] 認証
app.UseAuthorization(); // 認可

// 「Razor Pages」のコード
// app.MapRazorPages();
// 「MVC」のコード
// app.MapControllerRoute(
//     name: "default",
//     pattern: "{controller=Home}/{action=Index}/{id?}");

// === 省略 ===

Como queremos adicionar a funcionalidade de autenticação ao aplicativo, app.UseAuthentication() adicionaremos o . O local de descrição está de acordo com a documentação do MSDN, aplicativo. UseAuthorization(). Fora isso, ainda é um modelo.

Programas para projetos Razor Pages

Criar uma página de login (Pages/Account/Login.cshtml.cs)

Criar um arquivo

Crie uma página de login. O caminho do arquivo deve ser criado como "/Pages/Account/Login.cshtml". Isso ocorre porque o caminho de login padrão é assim. Se você quiser alterar esse caminho, poderá Program.cs fazê-lo definindo o AddCookie argumento do método de .

Você pode criá-lo copiando outros arquivos em vez de criá-lo a partir do menu, mas nesse caso, corrija o programa corretamente.

Permitir que os usuários acessem a página de login sem fazer login

Program.cs Como todas as páginas só podem ser acessadas quando você está logado, você precisa definir apenas a página de login para que você possa acessá-la mesmo que você não esteja logado.

AllowAnonymous Ao adicionar atributos, a página de destino pode ser acessada mesmo que não esteja autenticada. AllowAnonymous Os atributos podem ser usados em outros locais além da tela de login, como operações de API não relacionadas à autenticação de cookies.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;

namespace AspNetCoreCookieAuthenticationRazorPages.Pages.Account
{
  [AllowAnonymous]
  public class LoginModel : PageModel
  {
  }
}

Criar uma variável para receber entrada

Ao fazer login, você declara seu nome de usuário para poder receber esses valores porque digita sua senha.

// 省略

[AllowAnonymous]
public class LoginModel : PageModel
{
  /// <summary>ユーザー名。</summary>
  [BindProperty]
  [Required]
  [DisplayName("ユーザー名")]
  public string UserName { get; set; } = "";

  /// <summary>パスワード。</summary>
  [BindProperty]
  [Required]
  [DataType(DataType.Password)]
  [DisplayName("パスワード")]
  public string Password { get; set; } = "";
}

Definir um nome de usuário e senha para autenticação de login

Originalmente, ele seria armazenado em um banco de dados, etc., mas como o julgamento do usuário não é o foco principal desta vez, vou fazê-lo como um lugar temporário.

// 省略

[AllowAnonymous]
public class LoginModel : PageModel
{
  // 省略

  /// <summary>仮のユーザーデータベースとする。</summary>
  private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };
}

Processo de login

/// <summary>ログイン処理。</summary>
public async Task<ActionResult> OnPost()
{
  // 入力内容にエラーがある場合は処理を中断してエラー表示
  if (ModelState.IsValid == false) return Page();

  // ユーザーの存在チェックとパスワードチェック (仮実装)
  // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
  if (UserAccounts.TryGetValue(UserName, out string? getPass) == false || Password != getPass)
  {
    ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
    return Page();
  }

  // サインインに必要なプリンシパルを作る
  var claims = new[] { new Claim(ClaimTypes.Name, UserName) };
  var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync(principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToPage("/Index");
}

Este é o processo de autenticação depois de pressionar o botão de login. Se o nome de usuário e a senha corresponderem, a autenticação será possível.

O código descrito é o código mínimo necessário para autenticaçãoClaimClaimsIdentityClaimsPrincipal e HttpContext.SignInAsync Ao chamar o método, um cookie é gerado e autenticado.

Se forem necessárias reivindicações adicionais ou se a expiração do cookie for necessária, parâmetros adicionais serão adicionados.

Depois de fazer login, você será redirecionado para , onde /Index a autenticação é necessária.

Processo de logout

/// <summary>ログアウト処理。</summary>
public async Task OnGetLogout()
{
  // 認証クッキーをレスポンスから削除
  await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
}

Logout Quando acessado com um manipulador, ele é processado para fazer logout. HttpContext.SignOutAsync Ao chamar o método, você pode excluir o cookie e retorná-lo a um estado em que você não está conectado.

Criando um modo de exibição

Não levamos em conta a aparência. Adicione campos para inserir seu nome de usuário e senha, conforme mostrado abaixo, e coloque um botão para fazer login. Você também deve ter um link para acessar sem fazer login para /Index teste.

Como é problemático inserir o nome de usuário e a senha, o valor inicial é definido.

@page
@model AspNetCoreCookieAuthenticationRazorPages.Pages.Account.LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-page="/Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

Criar um link de logout (/Pages/Shared/_Layout.cshtml)

Não faremos nenhuma alteração na tela inicial, mas colocaremos um link de logout na barra de navegação. Além disso, para testes, poste um link que leva você à tela de login sem fazer logout.

<!-- 中略 -->
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
  <ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
    </li>
    <!-- ここから追加 -->
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/Login" asp-page-handler="Logout">ログアウト</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/Login">ログアウトせずログインへ</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

É isso para o código Razor Pages.

Programas para Projetos MVC

Criando um modelo de login

Você criou um modelo para receber os valores inseridos na tela de login.

namespace AspNetCoreCookieAuthenticationMvc.Models
{
  public class LoginModel
  {
    /// <summary>ユーザー名。</summary>
    [Required]
    [DisplayName("ユーザー名")]
    public string UserName { get; set; } = "";

    /// <summary>パスワード。</summary>
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("パスワード")]
    public string Password { get; set; } = "";
  }
}

Criando um AccountController

Crie os controladores e as ações necessárias para criar a tela de login. Crie o nome AccountController do controlador como . Isso ocorre porque, por padrão, o nome do controlador e o nome da ação na tela de login são definidos como "~/Conta/Login". Se você quiser alterar esse caminho, você pode fazê-lo nas opções do AddCookie método em Program.cs. Por enquanto, vamos continuar com as configurações padrão.

Primeiro, vamos criar o lado do controlador.

using AspNetCoreCookieAuthenticationMvc.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace AspNetCoreCookieAuthenticationMvc.Controllers
{
  /// <remarks>
  /// <see cref="AllowAnonymous"/> 属性は Cookie 認証していなくてもアクセスできる Action (Controller) であることを示す。
  /// </remarks>
  [AllowAnonymous]
  public class AccountController : Controller
  {
  }
}

AllowAnonymous Ao conceder o atributo, todas as ações nele podem ser executadas sem serem autenticadas. Isso permite que você acesse apenas a tela de login sem autenticação.

AllowAnonymous Os atributos também podem ser usados em controladores somente de API que não estão relacionados à autenticação de cookies em outros locais que não a tela de login.

Em seguida, defina os usuários e senhas que podem fazer login. Originalmente, ele seria armazenado em um banco de dados, etc., mas como o julgamento do usuário não é o foco principal desta vez, vou fazê-lo como um lugar temporário.

[AllowAnonymous]
public class AccountController : Controller
{
  /// <summary>仮のユーザーデータベースとする。</summary>
  private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };
}

A seguir está uma ação que exibe a tela de login. Como ele é exibido apenas , ele retorna a exibição como está.

/// <summary>ログイン画面を表示します。</summary>
public IActionResult Login() => View();

Abaixo está o código a ser processado ao fazer login.

/// <summary>ログイン処理を実行します。</summary>
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
  // 入力内容にエラーがある場合は処理を中断してエラー表示
  if (ModelState.IsValid == false) return View(model);

  // ユーザーの存在チェックとパスワードチェック (仮実装)
  // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
  if (UserAccounts.TryGetValue(model.UserName, out string? getPass) == false || model.Password != getPass)
  {
    ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
    return View(model);
  }

  // サインインに必要なプリンシパルを作る
  var claims = new[] { new Claim(ClaimTypes.Name, model.UserName) };
  var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync(principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToAction(nameof(HomeController.Index), "Home");
}

Este é o processo de autenticação depois de pressionar o botão de login. Se o nome de usuário e a senha corresponderem, a autenticação será possível.

O código descrito é o código mínimo necessário para autenticaçãoClaimClaimsIdentityClaimsPrincipal e HttpContext.SignInAsync Ao chamar o método, um cookie é gerado e autenticado.

Se forem necessárias reivindicações adicionais ou se a expiração do cookie for necessária, parâmetros adicionais serão adicionados.

Depois de fazer login, você será redirecionado para , onde ~/Home/Index a autenticação é necessária.

Finalmente, o processo de logout é adicionado.

/// <summary>ログアウト処理を実行します。</summary>
public async Task<IActionResult> Logout()
{
  // 認証クッキーをレスポンスから削除
  await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

  // ログイン画面にリダイレクト
  return RedirectToAction(nameof(Login));
}

HttpContext.SignOutAsync Ao chamar o método, você pode excluir o cookie e retorná-lo a um estado em que você não está conectado.

Criar um modo de exibição (formulário de login) (/Views/Account/Login.cshtml)

Login Clique com o botão direito do mouse na ação para adicionar um modo de exibição. Você também pode criá-lo copiando-o de outro arquivo.

Não levamos em conta a aparência. Adicione campos para inserir seu nome de usuário e senha, conforme mostrado abaixo, e coloque um botão para fazer login. Você também deve ter um link para acessar sem fazer login para Home/Index teste.

Como é problemático inserir o nome de usuário e a senha, o valor inicial é definido.

@model LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-controller="Home" asp-action="Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

Criar um link de logout (/Views/Shared/_Layout.cshtml)

Não faremos nenhuma alteração na tela inicial, mas colocaremos um link de logout na barra de navegação. Além disso, para testes, poste um link que leva você à tela de login sem fazer logout.

<!-- 中略 -->
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
  <ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
    </li>
    <!-- ここから追加 -->
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="Logout">ログアウト</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">ログアウトせずログインへ</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

É isso para o código MVC.

Confirmação de operação

Isso conclui a implementação mínima necessária da autenticação de cookies. Tente executá-lo e veja como ele funciona. O comportamento deve mudar dependendo se você está conectado ou não. Como um exemplo simples, você pode ver o seguinte comportamento.

Resultado da operação da operação
Vá para casa sem fazer login Redirecionar para a tela de login
login Ir para a tela inicial
Saia de casa e vá para casa sem fazer login Redirecionar para a tela de login
Vá para casa sem sair de casa e fazer login Ir para a tela inicial