ASP.NET core 2.1とloginsrvで認証機能を作る
loginsrvではトークンがCookieに保存されるのでASP.NET core側ではこれを読み取りパースする必要がある.
こんなかんじ.
code: Setup.cs
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(Options =>
{
Options.LoginPath = "/login";
Options.LogoutPath = "/login?logout=true";
Options.Cookie = new CookieBuilder
{
Name = "jwt_token"
};
Options.TicketDataFormat = new CustomJwtDataFormat(
SecurityAlgorithms.HmacSha512,
new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration"Jwt:Key")) });
});
ただしこのコードはASP.NET core 2.1だと(?)AuthenticationPropertiesが曖昧なので,これを直して以下のような感じ.
code:CustomJwtDataFormat.cs
public class CustomJwtDataFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string algorithm;
private readonly TokenValidationParameters validationParameters;
public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
{
this.algorithm = algorithm;
this.validationParameters = validationParameters;
}
public AuthenticationTicket Unprotect(string protectedText)
=> Unprotect(protectedText, null);
public AuthenticationTicket Unprotect(string protectedText, string purpose)
{
var handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;
try
{
principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);
var validJwt = validToken as JwtSecurityToken;
if (validJwt == null)
{
throw new ArgumentException("Invalid JWT");
}
if (!validJwt.Header.Alg.Equals(algorithm, StringComparison.Ordinal))
{
throw new ArgumentException($"Algorithm must be '{algorithm}'");
}
// Additional custom validation of JWT claims here (if any)
}
catch (SecurityTokenValidationException)
{
return null;
}
catch (ArgumentException)
{
return null;
}
// Validation passed. Return a valid AuthenticationTicket:
return new AuthenticationTicket(principal, new Microsoft.AspNetCore.Authentication.AuthenticationProperties(), "Cookie");
}
// This ISecureDataFormat implementation is decode-only
public string Protect(AuthenticationTicket data)
{
throw new NotImplementedException();
}
public string Protect(AuthenticationTicket data, string purpose)
{
throw new NotImplementedException();
}
}
コントローラー側では以下のような感じでユーザー情報を取得できる.
code: UserinfoController.cs
public class UserinfoController : Controller
{
public User Get()
{
var currentUser = HttpContext.User;
return new User{
Sub = currentUser.FindFirstValue(ClaimTypes.NameIdentifier),
Email = currentUser.FindFirstValue(ClaimTypes.Email),
Origin = currentUser.FindFirstValue("origin"),
Picture = currentUser.FindFirstValue("pircure")};
}
public class User
{
public string Sub { get; set; }
public string Email { get; set; }
public string Origin { get; set; }
public string Picture { get; set; }
}
}
あとは普段通りnginxとかでloginsrvとASP.NET coreアプリをリバースプロキシすればOK.