Razor Pagesでアプリケーション独自のアカウントで認証する - ASP.NET Core

Razor Pagesでアプリケーション独自のアカウントで認証するコードを紹介します。

概要

こちらの記事では、Razor Pagesでのシンプルな認証のアプリケーションを実装しました。 この記事では、シンプルな実装から処理を追加して、アプリケーション独自のアカウントで認証するコードを紹介します。

プログラム例

ASP.NET Core アプリケーションを作成します。
ファイル構成は下図の通りです。

コード

以下のコードを記述します。
/Account/Login.cshtml
@page
@model AuthenticationApp.Pages.Account.LoginModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
}
<html>
  <head></head>
  <body>
    <h1>ログイン</h1>
    <form method="post">
      ID:<input type="text"  asp-for="InputUserID"/><br/>
      Password:<input type="password" asp-for="InputPassword"/><br/>
      @if (Model.OutMessage!=""){
        <div>@Model.OutMessage</div>
      }
      <input type="submit" value="ログイン" /><br/>
    </form>
  </body>
</html>
/Account/Login.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

namespace AuthenticationApp.Pages.Account
{
  public class LoginModel : PageModel
  {
    [BindProperty]
    public string InputUserID { get; set; }
    [BindProperty]
    public string InputPassword { get; set; }
    public string OutMessage { get; set; } = "";

    public void OnGet()
    {
    
    }

    public IActionResult OnPost(string ReturnUrl)
    {
      List<UserInfo> userList = new List<UserInfo>();
      userList.Add(new UserInfo("penta", "pen123", "ぺんた"));
      userList.Add(new UserInfo("tori", "tor123", "とりっち"));
      userList.Add(new UserInfo("morgan", "mog123", "もーがん"));
      userList.Add(new UserInfo("lucy", "luc123", "るーしー"));

      UserInfo authUserInfo = null;
      foreach (UserInfo ui in userList) {
        if (ui.id == InputUserID && ui.password == InputPassword) {
          authUserInfo = ui;
        }
      }

      if (authUserInfo != null) {
        Claim[] claims = {
        new Claim(ClaimTypes.NameIdentifier, authUserInfo.id),
        new Claim(ClaimTypes.Name, authUserInfo.name)
        };

        ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

        HttpContext.SignInAsync(
          CookieAuthenticationDefaults.AuthenticationScheme,
          new ClaimsPrincipal(claimsIdentity),
          new AuthenticationProperties {
            IsPersistent = true
          }
        );

        if (ReturnUrl == null || ReturnUrl == "") {
          return RedirectToPage("/Index");
        }
        else {
          return Redirect(ReturnUrl);
        }

      }
      else {
        OutMessage = "IDまたはパスワードが違います。";
        return Page();
      }
    }

  }
}
/Account/Logout.cshtml
@page
@model AuthenticationApp.Pages.Account.LogoutModel
@{
}
<html>
  <head>

  </head>
  <body>
    <h1>Logout</h1>
    <p>ログアウトしました。</p>
  </body>
</html>
/Account/Logout.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;

namespace AuthenticationApp.Pages.Account
{
  public class LogoutModel : PageModel
  {
    public void OnGet()
    {
      HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
  }
}
/Content.cshtml
@page
@model AuthenticationApp.Pages.ContentModel
@{
}
<html>
  <head>

  </head>
  <body>
    <h1>コンテンツのページ</h1>
    <p>ユーザー:@Model.OutUserName</p>
    <p>コンテンツのページです</p>
    <p>認証が必要なページです</p>
  </body>
</html>
/Content.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

namespace AuthenticationApp.Pages
{
  [Authorize]
  public class ContentModel : PageModel
  {
    public string OutUserName { get; set; }

    public void OnGet()
    {
      foreach (Claim c in User.Claims) {
        if (c.Type == ClaimTypes.Name) OutUserName = c.Value;
      }
    }
  }
}
/Index.cshtml
@page
@model AuthenticationApp.Pages.IndexModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
}
<html>
  <head></head>
  <body>
    <h1>index</h1>
    <a asp-page="/Account/Login">Login</a><br/>
    <a asp-page="/Account/Logout">Logout</a><br/>
    <a asp-page="/Content">Content</a><br/>
  </body>
</html>
/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace AuthenticationApp.Pages
{
    public class IndexModel : PageModel
    {
        public void OnGet()
        {
        }
    }
}
Program.cs
using Microsoft.AspNetCore.Authentication.Cookies;

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
WebApplication app = builder.Build();

app.UseRouting();

app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.Run();
UserInfo.cs
namespace AuthenticationApp
{
  public class UserInfo
  {
    public string id;
    public string password;
    public string name;

    public UserInfo(string id, string password, string name)
    {
      this.id = id;
      this.password = password;
      this.name = name;
    } 
  }
}

解説

ログイン処理、ログアウト処理の基本的な動作はこちらの記事を参照してください。

今回、ログイン用のアカウントは簡易的な実装になっています。UserInfo オブジェクトのリストを用意し、 UserUnfoオブジェクトを作成し、ユーザーIDやパスワードを設定し、アプリケーションで利用できるアカウントを作成しています。

テキストボックスで入力した、ID、パスワードが一致しているか確認し、一致していれば、認証できたアカウントとして、UserInfo オブジェクトを authUserInfo 変数に代入します。
ID、パスワード判定の後、authUserInfo 変数がnullでなければ認証できたと判断し、ログイン処理を実行します。 ログイン処理中のClaimオブジェクトには、authUserInfo 変数のUserInfoオブジェクトの値を利用してアカウント情報を記録します。

ログイン成功時には、ReturnUrl パラメーターがある場合は、ReturnUrlにリダイレクトします。 ReturnUrlパラメーターがない場合はトップページの"/Index"にリダイレクトします。
public IActionResult OnPost(string ReturnUrl)
{
  List<UserInfo> userList = new List<UserInfo>();
  userList.Add(new UserInfo("penta", "pen123", "ぺんた"));
  userList.Add(new UserInfo("tori", "tor123", "とりっち"));
  userList.Add(new UserInfo("morgan", "mog123", "もーがん"));
  userList.Add(new UserInfo("lucy", "luc123", "るーしー"));

  UserInfo authUserInfo = null;
  foreach (UserInfo ui in userList) {
    if (ui.id == InputUserID && ui.password == InputPassword) {
      authUserInfo = ui;
    }
  }

  if (authUserInfo != null) {
    /* ログイン処理 */

    if (ReturnUrl == null || ReturnUrl == "") {
      return RedirectToPage("/Index");
    }
    else {
      return Redirect(ReturnUrl);
    }
  }
  else {
    OutMessage = "IDまたはパスワードが違います。";
    return Page();
  }
}

実行結果

プロジェクトを実行し、アプリケーションルートのURLにアクセスします。
下図のページが表示されます。


[Content]のリンクをクリックします。未ログイン状態の場合、リダイレクトされ、ログイン画面が表示されます。


IDとパスワードを入力します。入力後[ログイン]ボタンをクリックします。


コンテンツページが表示されます。ログインしたユーザー名が表示されることが確認できます。


トップページに戻り、[Logout]リンクをクリックします。ログアウトメッセージが表示されます。



再度ログイン画面にアクセスし、別のID、パスワードでログインします。



コンテンツのページにアクセスすると、ユーザー名がログインした別のユーザー名に変わることが確認できます。


ログアウトし、別のユーザーでログインしますが、IDやパスワードを間違えます。


IDを間違えるとログインできず、エラーメッセージが画面に表示されます。


正しいIDとパスワードでログインできると、ログインしたユーザー名が表示されます。


アプリケーション独自のアカウントでの認証を実装できました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-08-05
作成日: 2022-08-05
iPentec all rights reserverd.