Sukurkite prisijungimo mechanizmą naudodami slapukų autentifikavimą ir sukurkite mechanizmą, kuris bus nukreiptas, jei nesate autentifikuotas

Puslapis atnaujintas :
Puslapio sukūrimo data :

Darbo aplinka

Vizualinė studija
  • "Visual Studio" bendruomenė 2022 m
ASP.NET Core (MVC, Razor puslapiai)
6.0

Iš pradžių

Šį kartą "ASP.NET Core" naudos slapukų autentifikavimą kaip prisijungimo autentifikavimo mechanizmą. Galite manyti, kad slapukų autentifikavimas yra panašus į tradicinių formų autentifikavimą.

Kitas "ASP.NET Core" autentifikavimo mechanizmas yra "ASP.NET Core Identity". Be autentifikavimo naudojant formas, tai leidžia autentifikuoti naudojant API, naudotis išorinėmis prisijungimo paslaugomis, tvarkyti ir iš naujo nustatyti slaptažodžius ir kt. Galite naudoti daug funkcijų. Tačiau šį kartą tiesiog sukūrus paprastą prisijungimo ekraną, tai bus šiek tiek perdėtas autentifikavimo mechanizmas. Šį kartą jo nenaudosime.

Šį kartą pateiktuose slapukų autentifikavimo patarimuose negalite rodyti nieko kito, išskyrus prisijungimo ekraną, nebent prisijungiate. Jei bandysite pereiti į kitą ekraną, būsite nukreipti į prisijungimo ekraną. Jei prisijungiate, galite peržiūrėti kitus ekranus.

Kol kas galite prisijungti prisijungimo ekrane įvesdami savo vartotojo vardą ir slaptažodį. Pats vartotojo autentifikavimas įgyvendinamas kaip laikina vieta. Šiuo atveju pagrindinis dėmesys skiriamas slapukų autentifikavimo įgyvendinimui, todėl nustatymo proceso esmė, pavyzdžiui, ar slaptažodis yra teisingas, nėra esmė.

Šis patarimas apibūdina tik dalį programos. Norėdami gauti visą kodą, atsisiųskite visą programą. Jis taip pat apima tiek MVC, tiek "Razor Pages" sistemas.

Projekto kūrimas

Paleiskite "Visual Studio" ir sukurkite naują projektą.

"Razor Pages" pasirinkite ASP.NET "Core Web App", o MVC – ASP.NET "Core Web App" (modelis-rodinys-valdiklis).

Nurodykite pasirinktą projekto pavadinimą ir projekto vietą.

Norėdami nustatyti autentifikavimo tipą, pasirinkite "Nėra". Jei pasirinksite kitą autentifikavimą, naudosite ASP.NET Core Identity". Kai baigsite nustatymus, spustelėkite mygtuką "Sukurti".

Sukūrus projektą, toliau parodytas ekranas bus rodomas, kai bus vykdomas derinimas. Pagal šį ekraną sukursime programą.

Redaguoti programą.cs ("Razor" puslapiai, "MVC Common")

Pridėkite apibrėžimus, reikalingus slapukų autentifikavimui, į Programą .cs. Įtraukiamos šios vardų sritys:

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

builder.Services Štai kodas, kurį reikia įtraukti į .

// === 省略 ===

// 「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 Slapukų autentifikavimą galite įjungti vykdydami ir metodą. Jei jums nereikia keisti schemos pavadinimo, CookieAuthenticationDefaults.AuthenticationScheme nurodykite .

AddAuthorization Jei nurodote options.FallbackPolicy RequireAuthenticatedUser metodą Autentifikavimui reikalingą strategiją galite taikyti visiems puslapiams, visiems valdikliams ir veiksmams. Jei norite reikalauti autentifikavimo niekam kitam, išskyrus prisijungimo ekraną, tai yra naudingas būdas sumažinti kodą ir išvengti klaidų aprašyme. Turėsite atskirai parašyti kodą, kuriam nereikia autentifikuoti prisijungimo ekrano.

Toliau pateikiamas app kodas.

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

Kadangi norime prie programos pridėti autentifikavimo funkciją, app.UseAuthentication() pridėsime . Aprašymo vieta yra pagal MSDN dokumentaciją, programą. UseAuthorization(). Išskyrus tai, tai vis tiek yra šablonas.

"Razor Pages" projektų programos

Sukurkite prisijungimo puslapį (Pages/Account/Login.cshtml.cs)

Failo kūrimas

Sukurkite prisijungimo puslapį. Failo kelias turėtų būti sukurtas kaip "/Pages/Account/Login.cshtml". Taip yra todėl, kad numatytasis prisijungimo kelias yra toks. Jei norite pakeisti šį kelią, Program.cs galite tai padaryti nustatydami metodo argumentą AddCookie .

Galite jį sukurti nukopijuodami kitus failus, o ne kurdami jį iš meniu, tačiau tokiu atveju pataisykite programą teisingai.

Leiskite vartotojams pasiekti prisijungimo puslapį neprisijungus

Program.cs Kadangi visus puslapius galima pasiekti tik prisijungus, turite nustatyti tik prisijungimo puslapį, kad galėtumėte jį pasiekti, net jei nesate prisijungę.

AllowAnonymous Pridėjus atributų, tikslinį puslapį galima pasiekti, net jei jis nėra autentifikuotas. AllowAnonymous Atributai gali būti naudojami kitose vietose nei prisijungimo ekranas, pvz., API operacijose, nesusijusiose su slapukų autentifikavimu.

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
  {
  }
}

Sukurkite kintamąjį, kad gautumėte įvestį

Kai prisijungiate, deklaruojate savo vartotojo vardą, kad galėtumėte gauti šias reikšmes, nes įvedate slaptažodį.

// 省略

[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; } = "";
}

Apibrėžkite prisijungimo autentifikavimo vartotojo vardą ir slaptažodį

Iš pradžių jis būtų saugomas duomenų bazėje ir pan., Bet kadangi šį kartą vartotojo sprendimas nėra pagrindinis dėmesys, aš padarysiu jį kaip laikiną vietą.

// 省略

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

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

Prisijungimo procesas

/// <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");
}

Tai yra autentifikavimo procesas paspaudus prisijungimo mygtuką. Jei vartotojo vardas ir slaptažodis sutampa, autentifikuoti galima.

Aprašytas kodas yra minimalus kodas, reikalingas autentifikavimui,ClaimClaimsIdentityClaimsPrincipal ir HttpContext.SignInAsync Iškviečiant šį metodą, sugeneruojamas ir autentifikuojamas slapukas.

Jei reikia papildomų pretenzijų arba reikia pasibaigti slapukų galiojimo laikui, pridedami papildomi parametrai.

Prisijungę būsite nukreipti į , kur /Index reikalingas autentifikavimas.

Atsijungimo procesas

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

Logout Kai pasiekiama naudojant tvarkytoją, jis apdorojamas, kad atsijungtų. HttpContext.SignOutAsync Paskambinę šiuo metodu, galite ištrinti slapuką ir grąžinti jį į būseną, kurioje nesate prisijungę.

Rodinio kūrimas

Mes neatsižvelgiame į išvaizdą. Pridėkite laukus, kad įvestumėte savo vartotojo vardą ir slaptažodį, kaip parodyta toliau, ir įdėkite mygtuką, kad prisijungtumėte. Taip pat turėtumėte turėti nuorodą, kad galėtumėte pasiekti neprisijungę, kad galėtumėte išbandyti /Index .

Kadangi sunku įvesti vartotojo vardą ir slaptažodį, nustatoma pradinė vertė.

@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"); }
}

Atsijungimo nuorodos kūrimas (/Pages/Shared/_Layout.cshtml)

Neatliksime jokių pagrindinio ekrano pakeitimų, bet naršymo juostoje įdėsime atsijungimo nuorodą. Be to, norėdami išbandyti, paskelbkite nuorodą, nukreipiančią į prisijungimo ekraną neatsijungdami.

<!-- 中略 -->
<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>
<!-- 中略 -->

Viskas dėl "Razor Pages" kodo.

MVC projektų programos

Prisijungimo modelio kūrimas

Sukūrėte modelį, kad gautumėte prisijungimo ekrane įvestas reikšmes.

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; } = "";
  }
}

"AccountController" kūrimas

Sukurkite valdiklius ir veiksmus, reikalingus prisijungimo ekranui sukurti. Sukurkite valdiklio pavadinimą AccountController kaip . Taip yra todėl, kad pagal numatytuosius nustatymus valdiklio vardas ir veiksmo pavadinimas prisijungimo ekrane yra nustatyti į "~/Account/Login". Jei norite pakeisti šį kelią, galite tai padaryti metodo parinktyse AddCookie , esančiose Programa.cs. Kol kas tęsime numatytuosius nustatymus.

Pirmiausia sukurkime valdiklio pusę.

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 Suteikus atributą, visi jame esantys veiksmai gali būti atliekami be autentifikavimo. Tai leidžia pasiekti tik prisijungimo ekraną be autentifikavimo.

AllowAnonymous Atributai taip pat gali būti naudojami tik API valdikliuose, nesusijusiuose su slapukų autentifikavimu kitose vietose, išskyrus prisijungimo ekraną.

Tada apibrėžkite vartotojus ir slaptažodžius, kurie gali prisijungti. Iš pradžių jis būtų saugomas duomenų bazėje ir pan., Bet kadangi šį kartą vartotojo sprendimas nėra pagrindinis dėmesys, aš padarysiu jį kaip laikiną vietą.

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

Toliau pateikiamas veiksmas, rodantis prisijungimo ekraną. Kadangi jis tik rodomas, jis grąžina vaizdą tokį, koks yra.

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

Žemiau pateikiamas kodas, kurį reikia apdoroti prisijungiant.

/// <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");
}

Tai yra autentifikavimo procesas paspaudus prisijungimo mygtuką. Jei vartotojo vardas ir slaptažodis sutampa, autentifikuoti galima.

Aprašytas kodas yra minimalus kodas, reikalingas autentifikavimui,ClaimClaimsIdentityClaimsPrincipal ir HttpContext.SignInAsync Iškviečiant šį metodą, sugeneruojamas ir autentifikuojamas slapukas.

Jei reikia papildomų pretenzijų arba reikia pasibaigti slapukų galiojimo laikui, pridedami papildomi parametrai.

Prisijungę būsite nukreipti į , kur ~/Home/Index reikalingas autentifikavimas.

Galiausiai pridedamas atsijungimo procesas.

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

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

HttpContext.SignOutAsync Paskambinę šiuo metodu, galite ištrinti slapuką ir grąžinti jį į būseną, kurioje nesate prisijungę.

Sukurti rodinį (prisijungimo forma) (/Views/Account/Login.cshtml)

Login Dešiniuoju pelės mygtuku spustelėkite veiksmą, kad įtrauktumėte rodinį. Taip pat galite jį sukurti nukopijuodami iš kito failo.

Mes neatsižvelgiame į išvaizdą. Pridėkite laukus, kad įvestumėte savo vartotojo vardą ir slaptažodį, kaip parodyta toliau, ir įdėkite mygtuką, kad prisijungtumėte. Taip pat turėtumėte turėti nuorodą, kad galėtumėte pasiekti neprisijungę, kad galėtumėte išbandyti Home/Index .

Kadangi sunku įvesti vartotojo vardą ir slaptažodį, nustatoma pradinė vertė.

@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"); }
}

Atsijungimo saito kūrimas (/Views/Shared/_Layout.cshtml)

Neatliksime jokių pagrindinio ekrano pakeitimų, bet naršymo juostoje įdėsime atsijungimo nuorodą. Be to, norėdami išbandyti, paskelbkite nuorodą, nukreipiančią į prisijungimo ekraną neatsijungdami.

<!-- 中略 -->
<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>
<!-- 中略 -->

Viskas MVC kodui.

Operacijos patvirtinimas

Tai užbaigia minimalų būtiną slapukų autentifikavimo įgyvendinimą. Pabandykite jį paleisti ir pažiūrėkite, kaip jis veikia. Elgesys turėtų keistis priklausomai nuo to, ar esate prisijungę, ar ne. Kaip paprastą pavyzdį galite matyti tokį elgesį.

Operacijos rezultatas
Grįžkite namo neprisijungę Peradresuoti į prisijungimo ekraną
Prisijungti Eikite į pagrindinį ekraną
Atsijunkite nuo namų ir eikite namo neprisijungę Peradresuoti į prisijungimo ekraną
Eikite namo neatsijungę nuo namų ir neprisijungę Eikite į pagrindinį ekraną