JWTを使用しているasp.netコアを使用してWeb APIを実装しています。学習しようとしているので、IdentityServer4などのサードパーティのソリューションを使用していません。
JWT構成が機能するようになりましたが、JWTの有効期限が切れたときに更新トークンを実装する方法に困惑しています。
以下は、startup.cs内の私のConfigureメソッドのサンプルコードです。
app.UseJwtBearerAuthentication(new JwtBearerOptions()
{
AuthenticationScheme = "Jwt",
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = Configuration["Tokens:Audience"],
ValidIssuer = Configuration["Tokens:Issuer"],
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])),
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
}
});
以下は、JWTの生成に使用されるControllerメソッドです。テスト用に有効期限を30秒に設定しました。
[Route("Token")]
[HttpPost]
public async Task<IActionResult> CreateToken([FromBody] CredentialViewModel model)
{
try
{
var user = await _userManager.FindByNameAsync(model.Username);
if (user != null)
{
if (_hasher.VerifyHashedPassword(user, user.PasswordHash, model.Password) == PasswordVerificationResult.Success)
{
var userClaims = await _userManager.GetClaimsAsync(user);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}.Union(userClaims);
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwt.Key));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _jwt.Issuer,
audience: _jwt.Audience,
claims: claims,
expires: DateTime.UtcNow.AddSeconds(30),
signingCredentials: creds
);
return Ok(new
{
access_token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
});
}
}
}
catch (Exception)
{
}
return BadRequest("Failed to generate token.");
}
いくつかのガイダンスに非常に感謝します。
まず、リフレッシュトークンを生成し、どこかに保存する必要があります。これは、必要に応じて無効にできるようにするためです。すべてのデータがトークン内に含まれるアクセストークンと同じパターンに従う場合、間違った手に渡るトークンを使用して、更新トークンの有効期間中に新しいアクセストークンを生成できます。本当に長い時間になることがあります。
では、何を固執する必要がありますか?
GUIDで問題ありません。新しいアクセストークン、ほとんどの場合はユーザー名を発行できるデータも必要です。ユーザー名は、VerifyHashedPassword(...)部分をスキップできますが、残りの部分については同じロジックに従います。
更新トークンを取得するには、通常、スコープ「offline_access」を使用します。これは、トークン要求を行うときにモデル(CredentialViewModel)で提供するものです。通常のアクセストークンリクエストとは異なり、ユーザー名とパスワードを提供する必要はなく、代わりに更新トークンを提供します。更新トークンでリクエストを取得する場合、永続化された識別子を検索し、見つかったユーザーのトークンを発行します。
以下は、ハッピーパスの擬似コードです。
[Route("Token")]
[HttpPost]
public async Task<IActionResult> CreateToken([FromBody] CredentialViewModel model)
{
if (model.GrantType is "refresh_token")
{
// Lookup which user is tied to model.RefreshToken
// Generate access token from the username (no password check required)
// Return the token (access + expiration)
}
else if (model.GrantType is "password")
{
if (model.Scopes contains "offline_access")
{
// Generate access token
// Generate refresh token (random GUID + model.username)
// Persist refresh token
// Return the complete token (access + refresh + expiration)
}
else
{
// Generate access token
// Return the token (access + expiration)
}
}
}