ASP.NET jwtのログイン認証を実装する
ASP.NET
のSPAプロジェクトにjwtのログイン認証を実装する方法を紹介します。
基本的にはASP.NET SPAサイトにcookieベースのログイン認証を実装するで紹介したcookieベースの方法と同じです。
ライブラリの追加
Microsoft.AspNetCore.Authentication.JwtBearer
のライブラリが必要になるので、以下のURLを参考にプロジェクトにライブラリを追加します。
参考URL:https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.JwtBearer
Startup.csの修正
Startup.cs
に設定を追記します。
ValidIssuer
とValidAudience
はサイトのURLを設定しておくと良いかと思いますがlocalhost
などでも構いません。
IssuerSigningKey
には秘密鍵を設定しますので、実際は設定ファイルなどから読み込むようにしておくと良いかと思います。
デフォルトの認証をjwtにするためには23行目の設定ではなく25行目のように設定する必要があります。(23行目の設定方法だとcookie認証が有効になる)
Startup.cs(一部抜粋)
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
var jwtConfig = new JwtConfig();
Configuration.Bind("Jwt", jwtConfig);
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "https://zukucode.com",
ValidAudience = "https://zukucode.com",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890abcdefg")),
ClockSkew = TimeSpan.Zero
};
});
services.AddControllers(options =>
{
// すべてのアクセスに対してcookie認証保護を適用する
options.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()));
// すべてのアクセスに対してjwtの認証保護を適用する
options.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build()));
})
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)
{
app.UseRouting();
// app.UseRouting();の下に追加
app.UseAuthentication();
app.UseAuthorization();
認証トークンの発行
ログイン時に以下のように認証トークンを発行して、クライアントにレスポンスします。
issuer
やaudience
などはStartup.cs
で設定したものと同じ値を使用します。
public string GenerateToken(string userid)
{
var claims = new[] {
// 必要な認証情報を追加する
new Claim(ClaimTypes.Name, userid)
};
var token = new JwtSecurityToken(
"https://zukucode.com", // issuer
"https://zukucode.com", // audience
claims,
expires: DateTime.Now.AddSeconds(10000), // 有効期限
signingCredentials: new SigningCredentials("1234567890abcdefg", SecurityAlgorithms.HmacSha256) // Startup.csで設定したものと同じ値を設定
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
動作確認
cookie認証の場合と同じ手順になります。
プロジェクトを作成した際の雛形として作成されたWeatherForecastController
で動作確認を行います。
ここではAPI
としてajax
でアクセスするため、Route
の設定箇所に以下のようにapi
を追加します。
こうすると、api/WeatherForecast
でアクセスできるようになります。
[ApiController]
[Route("[controller]")]
[Route("api/[controller]")]
public class WeatherForecastController : ControllerBase
クライアント側で、ajaxのリクエストを投げます。
ここではajax
のライブラリにaxios
を使用します。
const response = axios.get('/api/WeatherForecast');
未認証の状態でアクセスをすると401(Unauthorized)のエラーになることが確認できます。
認証保護の除外
例えばログイン時のAPIなど、未認証の状態でもアクセスしたい場合があります。
その場合は対象のメソッドにAllowAnonymous
を設定します。
using Microsoft.AspNetCore.Authorization;
[HttpGet]
[AllowAnonymous]
public IEnumerable<WeatherForecast> Get()
AllowAnonymous
を設定後にアクセスするとデータが取得できることを確認できます。
ログイン/ログアウト処理
認証用のコントローラーを作成し、以下のようにログイン処理とログアウト処理を実装します。
「認証判定処理」の部分は実際にはデータベースなどでIDやパスワードを使って判定することになると思います。
AuthController.cs
[ApiController]
[Route("api/[controller]/[action]")]
public class AuthController : ControllerBase
{
public class LoginRequest
{
public string login_id { get; set; }
public string password { get; set; }
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(LoginRequest request)
{
if (認証判定処理(request.login_id, request.password) == false)
{
return BadRequest("ユーザー名またはパスワードが違います。");
}
return Ok(GenerateToken(login_id)); // 認証トークンをレスポンスする
}
}
クライアント側からは以下のようにログイン処理をコールします。
const response = await axios.post('/api/auth/Login', { login_id: 入力したログインID, password: 入力したパスワード });
ログイン処理に成功した場合、認証トークンがレスポンスされます。
次回以降のリクエストにはこの認証トークンをリクエストヘッダに含める必要があります。
axios
の場合は以下のように設定します。
axios.interceptors.request.use((request) => {
request.headers['Authorization'] = `Bearer ${token}`;
return request;
});
画面を再描画したときにログイン状態を保持したい場合は、認証トークンをlocalstorageなどに保存しておく必要があります。
セキュリティを考慮して、localstorageの代わりにhttponly
のcookieに保持したい場合は設定を少し変更する必要があります。
jwtをcookieで保持する方法はASP.NET jwtの認証トークンをcookieで保持する方法で紹介しています。