LoginSignup
4
4

More than 1 year has passed since last update.

[.NET 6] 認証情報を redis に保持しログアウト時に無効化する

Posted at

最近認証回りをちょこちょこ調べていて、しばやんさんの記事をベースに .NET 6 でおためし

ASP.NET Core アプリケーションのログアウト時に認証クッキーを確実に無効化する

やりたいこと

  • 認証情報を redis に保持する
  • ログアウト時に redis の値を削除し認証情報を無効にする

環境

  • Visual Studio 2022 / .NET 6
  • redis on docker

モジュール構成

Sample.csproj
└ Controllers
  └ AccountController.cs
  └ ValuesController.cs
└ RedisSessionStore.cs
└ Program.cs

コード

AccountController.cs

        public IActionResult Login()
        {
            var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new[]
            {
                new Claim(ClaimTypes.Name, "test taro"),
                new Claim(ClaimTypes.Role, "Administrator")
            }, CookieAuthenticationDefaults.AuthenticationScheme));
            var authenticationProperties = new AuthenticationProperties
            {
                IsPersistent = true,
                RedirectUri = Url.Action("Index", "Home")
            };

            return SignIn(claimsPrincipal, authenticationProperties, CookieAuthenticationDefaults.AuthenticationScheme);
        }

        public IActionResult Logout()
        {
            var authenticationProperties = new AuthenticationProperties
            {
                RedirectUri = Url.Action("Index", "Home")
            };

            return SignOut(authenticationProperties, CookieAuthenticationDefaults.AuthenticationScheme);
        }

  • 単純なログイン/ログアウト処理を定義
  • 認証情報の取り扱いを確認したいので、固定の Claim を使用する
ValuesController.cs

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        [HttpGet]
        public ActionResult Get() => Ok(new { name = User?.Identity?.Name });
    }

  • こちらも、単純に認証情報を取得するだけの処理を定義
RedisSessionStore.cs

    public class RedisSessionStore : ITicketStore
    {
        private readonly IDistributedCache redisCache;

        public RedisSessionStore(IDistributedCache redisCache) => this.redisCache = redisCache;

        // 認証情報を保存する
        public async Task<string> StoreAsync(AuthenticationTicket ticket)
        {
            // Guid をキーに認証情報を redis に保存する
            var key = Guid.NewGuid().ToString();
            await RenewAsync(key, ticket);
            return key;
        }

        // 認証情報を更新する
        public async Task RenewAsync(string key, AuthenticationTicket ticket)
        {
            // 有効期限を 5 分にして保存する
            var serializedTicket = TicketSerializer.Default.Serialize(ticket);
            await redisCache.SetAsync(key, serializedTicket, new DistributedCacheEntryOptions() { SlidingExpiration = TimeSpan.FromMinutes(5) });
        }

        // 認証情報を取得する
        public async Task<AuthenticationTicket?> RetrieveAsync(string key)
        {
            // キーに該当する認証情報を取得。なければ null を返す
            var serializedTicket = await redisCache.GetAsync(key);
            return serializedTicket != null ? TicketSerializer.Default.Deserialize(serializedTicket) : null;
        }

        // 認証情報を削除する
        public async Task RemoveAsync(string key) => await redisCache.RemoveAsync(key);
    }

  • ITicketStore を実装し、各メソッドで redis の操作を行う
Program.cs

builder.Services.AddSingleton<IDistributedCache, RedisCache>();
builder.Services.AddSingleton<ITicketStore, RedisSessionStore>();
builder.Services.AddStackExchangeRedisCache(options =>
{
    // docker で起動した redis を指定する
    options.Configuration = "127.0.0.1:6379";
});

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        // こちらも有効期限を 5 分で設定
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
    });
builder.Services.AddOptions<CookieAuthenticationOptions>(CookieAuthenticationDefaults.AuthenticationScheme)
    .Configure<ITicketStore>((options, store) => options.SessionStore = store);

  • nuget 参照で Microsoft.Extensions.Caching.StackExchangeRedis を追加しておく

redis

docker-compose.yml

version: '3'

services:
  redis:
    container_name: redis
    image: redis:latest
    ports:
      - 6379:6379
    volumes:
      - ./data/redis:/data

実行

  • /Account/Login にアクセス
    • Cookie の .AspNetCore.Cookies の値をコピー
  • Postman から /api/values にリクエスト
    • Key = Cookie / Value = .AspNetCore.Cookies=xxxxxxxxxxxxxxx を設定
    • "name": "test taro" がレスポンス
  • /Account/Logout にアクセス
  • Postman から /api/values にリクエスト
    • Key = Cookie / Value = .AspNetCore.Cookies=xxxxxxxxxxxxxxx を設定
    • "name": null がレスポンス
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4