创建在您未使用 cookie 身份验证登录时重定向的机制 (ASP.NET Core 3.0)

更新页 :
页面创建日期 :

环境

Visual Studio
  • 可视化工作室社区 2019
ASP.NET酷
3.0 或更高版本

Cookie 身份验证可以在 .NET Core 2.2 或更早版本中使用,但此提示在 .NET Core 3.0 及更高版本中提供专用代码。

入门

这一次ASP.NET Core 使用 Cookie身份验证作为登录身份验证机制。 您可以认为 Cookie 身份验证类似于传统的表单身份验证。

ASP.NET Core 身份验证的其他机制是ASP.NET核心标识。 除了使用表单进行身份验证外,您还可以使用 API 身份验证、外部登录服务、密码管理和重置等。 您可以使用许多功能。 但是,从创建简单的登录屏幕的角度来看,这是一个有点夸张的身份验证机制。 这次不使用它。

在 Cookie 身份验证提示中,除非登录,否则无法显示登录屏幕。 当您尝试转到其他屏幕时,您将被重定向到登录屏幕。 登录后,您还可以看到其他屏幕。

在登录屏幕上输入用户名和密码后,即可登录。 用户身份验证本身是临时实现的。 这一次,我们主要实现 Cookie 身份验证,因此确定密码是否正确等不是本质。

此提示部分列出了程序。 下载完整的程序的完整代码。

创建项目

启动 Visual Studio 并创建新项目。

image

选择ASP.NET核心 Web 应用程序

image

指定任何项目名称和项目位置。

image

这一次,我们将使用 MVC 项目,但大多数其他模板都可以替换它。

对于身份验证,请选择"无身份验证"。 如果选择其他身份验证,则使用 ASP.NET 核心标识。

image

创建项目后,调试将显示下图屏幕。 我们将基于此屏幕创建程序。

image

编辑Startup.cs

Startup.cs 中添加 Cookie 身份验证所需的定义。 命名空间使用:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

您可以通过运行 AddAuthentation 和 AddCookie 方法启用 Cookie 身份验证。 如果不需要更改方案名称,请指定 Cookie 身份验证 Defaults.身份验证 Scheme。

AddAuthorization 方法的选项。 如果为 FallbackPolicy 指定了 RequireAuthenticatedUser, 您可以将身份验证强制策略应用于所有控制器和操作。 如果登录屏幕以外的身份验证是必需的,则减少代码并防止错误也是一种有用的方法。 登录屏幕将单独编写不需要身份验证的代码。

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews();
  
  // Cookie による認証スキームを追加する
  services
    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie();
  
  services.AddAuthorization(options =>
  {
    // AllowAnonymous 属性が指定されていないすべての Action などに対してユーザー認証が必要となる
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
      .RequireAuthenticatedUser()
      .Build();
  });
}

向应用程序添加身份验证功能,以便应用。 添加 UseAuthentation()。 描述位置根据 MSDN 文档应用。 放置在 UseAuthoriation() 之前。 否则,它仍为模板。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  if (env.IsDevelopment())
  {
    app.UseDeveloperExceptionPage();
  }
  else
  {
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. ...
    app.UseHsts();
  }
  app.UseHttpsRedirection();
  app.UseStaticFiles();
  
  app.UseRouting();
  
  app.UseAuthentication(); // [追加] 認証
  app.UseAuthorization(); // 認可
  
  app.UseEndpoints(endpoints =>
  {
    endpoints.MapControllerRoute(
      name: "default",
      pattern: "{controller=Home}/{action=Index}/{id?}");
  });
}

创建帐户控制程序

创建创建登录屏幕所需的控制器和操作。 将控制器名称创建为"帐户控制器"。 这是因为默认情况下,登录屏幕的控制器和操作名称设置为"*/帐户/登录"。 如果要更改此路径,可以使用 Startup.cs 中的 AddCookie 方法选项进行更改。 我们将使用默认设置前进。

image

首先,创建控制器的一侧。 通过授予AllowAnonymous属性,即使未经过身份验证,也可以执行所有操作。 这仅允许登录屏幕在没有身份验证时访问。

AllowAnonymous属性与登录屏幕中的其他位置与 Cookie 身份验证无关。 它还可用于 API 专用控制器。

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

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

定义谁可以登录和密码。 最初,它存储在数据库等,但这次用户判断不是主要关注 我会用临时的放假做。

/// <summary>仮のユーザーデータベースとする。</summary>
private Dictionary<string, string> UserAccounts { get; set; }

public AccountController()
{
  // 仮のユーザーを登録する
  UserAccounts = new Dictionary<string, string>
  {
    { "user1", "password1" },
    { "user2", "password2" },
  };
}

显示登录屏幕的操作。 返回视图,因为它只是显示它。

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

按下登录按钮后的身份验证过程。 如果用户名和密码匹配,则启用身份验证。

以下代码是身份验证所需的最低代码,用于定义声明、标识和 Pricinpal。 调用 HttpContext.SignInAsync 方法生成并经过身份验证。

如果需要额外的声明或 Cookie 过期,请添加参数。

登录后,您将被重定向到需要身份验证的 */Home/Index。

/// <summary>ログイン処理を実行します。</summary>
[HttpPost]
public async Task<IActionResult> Login(string userName, string password)
{
  // ユーザーの存在チェックとパスワードチェック (仮実装)
  // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
  if (UserAccounts.TryGetValue(userName, out string getPass) == false || password != getPass)
  {
    return View();
  }

  // サインインに必要なプリンシパルを作る
  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 RedirectToAction(nameof(HomeController.Index), "Home");
}

包括注销操作。 您可以通过调用 HttpContext.SignOutAsync 方法删除 Cookie 并返回到未登录状态。

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

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

创建视图(登录表单)(/视图/帐户/登录.cshtml)

由于您并不特别考虑外观,因此请添加一个字段,用于输入用户名和密码,如下图所示,并放置一个按钮进行登录。 放置一个链接,用于访问 Home/Index,而无需登录进行测试。

我设置了初始值,因为输入用户名和密码很麻烦。

image

@{
  Layout = null;
}
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width" />
  <title>Login</title>
</head>
<body>
  <form method="post">
    <input name="userName" type="text" placeholder="ユーザー名" value="user1" />
    <input name="password" type="password" placeholder="パスワード" value="password1" />
    <button type="submit">ログイン</button>
  </form>
  <p><a asp-controller="Home" asp-action="Index">認証が必要な画面へ直接リンク</a></p>
</body>
</html>

创建注销链接 (/Views/Shared/_Layout.cshtml)

主屏幕不会更改,但将注销链接放在导航栏上。 此外,为了测试目的,请发布一个链接,该链接将转换为登录屏幕,而无需注销。

image

<!-- 中略 -->
<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">Logout</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">ログアウトせずログインへ</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

操作确认

现在,您已经完成了 Cookie 身份验证所需的最低实现。 运行并查看其工作原理。 您的行为应该取决于您是否登录。 一个简单的例子是,你可以检查以下行为。

操作 = 操作结果
无需登录即可回家 重定向到登录屏幕
登录 到主屏幕
注销主页,无需登录即可回家 重定向到登录屏幕
不要注销主页,无需登录即可回家 到主屏幕