在 [.NET 6] 中,将认证信息存储在Redis中,并在注销时将其作废
最近我一直在研究认证周边,并且以柴犬桑的文章为基础,在.NET 6上试用。
确保在ASP.NET Core应用程序注销时有效地使身份验证cookie无效。
我想要做的事情 (Wǒ zuò de
-
- 認証情報を redis に保持する
- ログアウト時に redis の値を削除し認証情報を無効にする
环境 – 一种选择
-
- Visual Studio 2022 / .NET 6
- redis on docker
模块组成
Sample.csproj
└ Controllers
└ AccountController.cs
└ ValuesController.cs
└ RedisSessionStore.cs
└ Program.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 を使用する
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult Get() => Ok(new { name = User?.Identity?.Name });
}
- こちらも、単純に認証情報を取得するだけの処理を定義
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 の操作を行う
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.
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 がレスポンス