2017-11-08 23 views
0

ASP.NET Core 2.0 Web APIでJWTトークン生成が機能していますが、後続の新しいアクセストークンが以前に生成されたものと同じ期限になる問題が発生していますもの。新しいJWTトークンのトークンが古いトークンと同じです

たとえば、ログイン資格情報を掲示し、アクセストークンを返します。アクセストークンは[承認] APIエンドポイントで期待通りに機能します。テスト目的のために、1分後に期限切れになるようにトークンを設定します。 1分後、トークンは期限切れとなり、認証されたエンドポイントは、予想どおりに401を返します。

クライアント側のアプリケーションで401を処理しています。ログインフォームが表示され、ユーザーが再度ログインします。新しいトークンが生成され、返されます。この新しいトークンは、最初に生成されたトークンと全く同じ 'ValidTo' DateTimeを持ちます。

Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:情報:検証に失敗しました。それは問題ではないですので、私は(予想、有効期限が切れたとしてトークン)間違ったトークン

最初のトークンの失敗を渡して、確認トークンeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZGFtQHBytNDRiYS1 ... Do1NzM5NS8ifQ.t8DjvlGV7GZ3xucwu-1hlJRXA5owPdP9t7kfYiiJHyQ。

Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException:IDX10223:有効期間の検証に失敗しました。トークンは期限切れです。

ValidTo:'11/08/2017年夜07時23分09' 秒

現在時刻:'11/08/2017年午前19時23' 分13秒。

セカンドトークンの失敗(期待できない、前のトークンと同じValidTo)

Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:情報は:トークンeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZGFtQ ... dDo1NzM5NS8ifQの検証に失敗しました。 3。

Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException:IDX10223:有効期間の検証に失敗しました。トークンは期限切れです。

ValidTo:'11/08/2017年夜07時23分09' 秒

現在時刻:'11/08/2017年19時23分34' 秒。 Startup.csで

JWTの構成トークンが作成され

services.Configure<JwtIssuerOptions>(options => { 
      options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; 
      options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)]; 
      options.SigningCredentials = new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256); 
      options.ValidFor = TimeSpan.FromMinutes(1); 
     }); 
     services.AddAuthentication(o => 
     { 
      o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
      o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
     }).AddJwtBearer(o => 
     { 
      o.TokenValidationParameters = new TokenValidationParameters 
      { 
       ValidateIssuer = true, 
       ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)], 

       ValidateAudience = true, 
       ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)], 

       ValidateIssuerSigningKey = true, 
       IssuerSigningKey = SigningKey, 

       RequireExpirationTime = true, 
       ValidateLifetime = true, 
       ClockSkew = TimeSpan.Zero, 
      }; 
     }); 

ログインアクション:

[HttpPost] 
    public async Task<IActionResult> Login([FromBody]CredentialsViewModel credentials) 
    { 
     if (!ModelState.IsValid) 
     { 
      return BadRequest(ModelState); 
     } 

     var identity = await GetClaimsIdentity(credentials.UserName, credentials.Password); 
     if (identity == null) 
     { 
      return BadRequest(Errors.AddErrorToModelState("login_failure", "Invalid username or password.", ModelState)); 
     } 

     // Serialize and return the response 
     var response = new 
     { 
      id = identity.Claims.Single(c => c.Type == "id").Value, 
      auth_token = await _jwtFactory.GenerateEncodedToken(credentials.UserName, identity), 
      expires_in = (int)_jwtOptions.ValidFor.TotalSeconds 
     }; 

     var json = JsonConvert.SerializeObject(response, _serializerSettings); 
     return new OkObjectResult(json); 
    } 
トークンが生成されている

JwtFactory方法:

private readonly JwtIssuerOptions _jwtOptions; 

public JwtFactory(IOptions<JwtIssuerOptions> jwtOptions) 
{ 
    _jwtOptions = jwtOptions.Value; 
    ThrowIfInvalidOptions(_jwtOptions); 
} 

public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity) 
    { 
     var claims = new[] 
    { 
      new Claim(JwtRegisteredClaimNames.Sub, userName), 
      new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()), 
      new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64), 
      identity.FindFirst("rol"), 
      identity.FindFirst("id") 
     }; 

     // Create the JWT security token and encode it. 
     var jwt = new JwtSecurityToken(
      issuer: _jwtOptions.Issuer, 
      audience: _jwtOptions.Audience, 
      claims: claims, 
      notBefore: _jwtOptions.NotBefore, 
      expires: _jwtOptions.Expiration, 
      signingCredentials: _jwtOptions.SigningCredentials); 

     var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); 

     return encodedJwt; 
    } 

答えて

0

問題私のjwtFactoryにあった、私は依存性注入でしたIOptions。これは起動時に定義され、オブジェクトの作成時に自動的に入力されるいくつかのプロパティ(DateTime.NowUtcを取得するIssuedAtなど)を持つため、IOptionsは最初に読み込まれたときの構成のみを返します。

私はIOptionsSnapshotを注入することでこれを解決することができました.IOptionsSnapshotは新しいバージョンのJwtIssuerOptionsを取得し、更新されたIssuedAtプロパティを持ちます。

private readonly JwtIssuerOptions _jwtOptions; 

    public JwtFactory(IOptionsSnapshot<JwtIssuerOptions> jwtOptions) 
    { 
     _jwtOptions = jwtOptions.Value; 
     ThrowIfInvalidOptions(_jwtOptions); 
    } 
-1

だけの提案、_jwtOptions.Expirationはそうのは、それが20だと数分で、その場合にはあなたがexpires: DateTime.UtcNow.AddMinutes(_jwtOptions.Expiration)または類似した何かを持っている必要がありましょう、のためにトークンが有効である必要があり、すなわちどのくらいの時間、タイムスパンでなければなりません。それを反映させるために名前を変更することさえできます。

+0

私のJwtIssuerOptionsモデルでは、有効期限はIssuedAt Datetimeをとり、ValidFor時間を自動的に追加するラムダです。 IssuedAtは単にモデル宣言のDateTime.UtcNowで初期化されます。したがって、私の場合は、ValidForのみを明示的に起動時に設定する必要があります。 JwtSecurityTokenはSystem.IdentityModel.Tokens.Jwt内のクラスであり、期限切れにはDateTimeが必要ですが、Timespanではなく、私が知っているのは – adam3039

+0

です。そのため、私はその設定値から 'datetime'を作成しています –

関連する問題