web-dev-qa-db-ja.com

JwtSecurityTokenは必要なときに期限切れになりません

現在、System.IdentityModels.Tokens名前空間でJwtSecurityTokenクラスを使用しています。次を使用してトークンを作成します。

DateTime expires = DateTime.UtcNow.AddSeconds(10);
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var genericIdentity = new System.Security.Principal.GenericIdentity(username, "TokenAuth");

ClaimsIdentity identity = new ClaimsIdentity(claims);
string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
var securityKey = new     InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
var signingCreds = new SigningCredentials(securityKey,     SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.HmacSha256Signature);
var securityToken = handler.CreateToken(
    issuer: issuer,
    audience: ConfigurationManager.AppSettings["UiUrl"].ToString(),
    signingCredentials: signingCreds,
    subject: identity,
    expires: expires,
    notBefore: DateTime.UtcNow
);
return handler.WriteToken(securityToken); 

何らかの理由で、有効期限が現在の時刻の10秒後に設定されていても、トークンが検証されるときに約5分まで実際に例外をスローしません。これを見た後、おそらく5分の最小有効期限があると思ったので、有効期限を次のように設定しました。

DateTime.UtcNow.AddMinutes(5);

その後、10分で期限切れになりますが、例外メッセージには、有効期限が想定される値(ユーザーがログインしてから5分後)に設定され、例外で現在の時刻が表示されると5分後になることが示されています有効期限。したがって、いつ期限切れになるべきかはわかっているようですが、実際には期限切れの5分後まで例外をスローしません。次に、トークンが期限切れに設定した時間に5分を追加しているように見えるため、期限切れ時間を次のように設定します。

DateTime.UtcNow.AddMinutes(-5).AddSecond(10);

私はこれをテストしましたが、まだ有効期限が切れていません(10分以上経った後)。誰かがこれが起こっている理由と私が間違っていることを説明してもらえますか?また、JWTとこのライブラリを使用するのは初めてなので、コードで他に何かを見つけた場合は、ガイダンスをいただければ幸いです。

前もって感謝します

23
tkd_aj

@Denis Kucherovの回答を読んだ後、JwtBearerOptionsクラスを使用せずに彼が投稿したのと同じカスタムバリデーターを使用でき、新しいライブラリを追加する必要があることがわかりました。

また、これらの同じクラスを多く含む2つの名前空間があるため、これらすべてがSystem.IdentityModels ...名前空間を使用していることを必ず説明します。 (Microsoft.IdentityModelsではありません...)

以下は私が使用してしまったコードです:

private bool CustomLifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken tokenToValidate, TokenValidationParameters @param)
{
    if (expires != null)
    {
        return expires > DateTime.UtcNow;
    }
    return false;
}
private JwtSecurityToken ValidateJwtToken(string tokenString)
{
   string secret = ConfigurationManager.AppSettings["jwtSecret"].ToString();
   var securityKey = new InMemorySymmetricSecurityKey(Encoding.Default.GetBytes(secret));
   JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
   TokenValidationParameters validation = new TokenValidationParameters()
   {
       ValidAudience = "MyAudience",
       ValidIssuer = "MyIssuer",
       ValidateIssuer = true,
       ValidateLifetime = true,
       LifetimeValidator = CustomLifetimeValidator,
       RequireExpirationTime = true,
       IssuerSigningKey = securityKey,
       ValidateIssuerSigningKey = true,
   };
   SecurityToken token;
   ClaimsPrincipal principal = handler.ValidateToken(tokenString, validation, out token);
   return (JwtSecurityToken)token;
}
6
tkd_aj

問題はClockSkewに関連しています。通常、検証ライブラリ(少なくともMSのもの)がクロックスキューを補正します。 ClockSkewのデフォルト値は5分です。回答をご覧ください こちら

ClockSkewTokenValidationParametersを変更できます:

var tokenValidationParameters = new TokenValidationParameters
{
    //...your setting

    // set ClockSkew is zero
    ClockSkew = TimeSpan.Zero
};

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = tokenValidationParameters
});

ハッピーコーディング!

39
hien

LifeTimeValidatorには何らかの問題があるようです。カスタムデリゲートでそのロジックをオーバーライドできます。また、JwtBearerOptionsクラスを使用して、認証ミドルウェアの動作を制御します。例えば:

new JwtBearerOptions
        {
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                ValidIssuer = _configuration["Tokens:Issuer"],
                ValidAudience = _configuration["Tokens:Audience"],
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                LifetimeValidator = LifetimeValidator,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Tokens:Key"]))
            }
        }

LifetimeValidotorデリゲートを割り当てて、独自のタイムアウト検証ロジックを提供します。

private bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken token, TokenValidationParameters @params)
    {
        if (expires != null)
        {
            return expires > DateTime.UtcNow;
        }
        return false;
    }
6
Denis Kucherov

JWTトークンミドルウェアも実装したばかりで、インターネットの例ではUtcNowを使用していますが、Nowを使用するか、有効期限が切れています。 Nowを使用すると、有効期限が切れます。

0
SledgeHammer