一式を https://github.com/ken200/OwinAuthWithNancy に配置しています。
本件に関連するソースコードは LoginMiddleware.cs と startup.cs に記載しています。
必要パッケージ
-
Microsoft.Owin
-
Microsoft.Owin.Security
-
Microsoft.Owin.Security.Cookies
-
Owin
構成物
ミドルウェア
Microsoft.Owin.OwinMiddlewareクラスを継承して作成するのが無難かと思われます。
KatanaProjectに依存することになるけど、MS製なのでさほど問題にはならないと考えています。
ミドルウェアでの認証関係について、複雑なことは行っていません。読んでもらえればわかるけど、SignInメソッドの「context.Authentication.SignIn(userIdentity);」で認証登録し、その後リダイレクトしています。
//ミドルウェアコードを一部抜粋
public class LoginMiddleware : OwinMiddleware
{
public LoginMiddleware(...)
: base(...)
{
...
}
public async override Task Invoke(IOwinContext context)
{
if(!IsAuthenticated(context))
{
await SignIn(context);
return;
}
await Next.Invoke(context);
}
...
private async Task SignIn(IOwinContext context)
{
//ログインユーザー名の取得
var userName = await _loginOption.UserNameGetter(context);
if (string.IsNullOrEmpty(userName))
{
//レスポンスに書き込み。次ミドルウェアへの伝番は行わない。
await WriteResponse(context.Response, 401, "invalid parameter.");
return;
}
//ユーザーストアに対象ユーザーが存在するか確認
var uMng = new MyUserManager();
var userIdentity = await uMng.CreateAsync(userName);
if (userIdentity == null)
{
await WriteResponse(context.Response, 401, "invalid user.");
return;
}
//認証登録
context.Authentication.SignIn(userIdentity);
//リダイレクト
var q = context.Request.Query[_loginOption.RedirectUrlQueryName];
var redirectPath = !string.IsNullOrEmpty(q) ? q : _loginOption.DefaultRedirectUrl;
context.Response.Redirect(redirectPath);
}
...
}
ユーティリティークラス
UseXXXX()な拡張メソッドを定義する。これ経由でミドルウェアを登録する慣わし?
public static class LoginExtentions
{
public static IAppBuilder UseLogin(this IAppBuilder app, LoginOptions loginOption, LogoutOptions logoutOption)
{
return app.Use<LoginMiddleware>(loginOption, logoutOption);
}
}
Startupクラスでの登録
public class Startup
{
public void Configuration(IAppBuilder app)
{
//クッキーベースの認証する際に必要なミドルウェア
app.UseCookieAuthentication(new CookieAuthenticationOptions() {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
//独自認証ミドルウェア
app.UseLogin(
new LoginOptions() {
LoginUrl = "/login",
LoginMethod = "POST",
UserNameGetter = async (ctx) => {
var form = await ctx.Request.ReadFormAsync();
return form.Get("userName");
},
DefaultRedirectUrl = "/secure"},
new LogoutOptions() {
LogoutUrl = "/logout",
DefaultRedirectUrl = "/" });
app.UseNancy();
}
}