2017-07-15 21 views
0

ASP.NET CoreでJWTベアラ認証を使用するアプリケーションを構築しています。ユーザーが複数のセッションを同時に開くのを防ぐ必要があります。 Microsoft.AspNetCore.Authentication.JwtBearerミドルウェアを使用してユーザーのすべてのトークンを一覧表示し、着信認証要求を無効にするためにそのユーザーに対して発行された他のトークンがあるかどうかを検証する方法があるかどうか疑問に思っています。ユーザーがJWTトークンで複数のセッションを持つことを防止する

サーバー上でクレームを検証することができれば、サーバーはそのクレームとそのクレームを所有しているユーザーの記録を持っていると思います。右?

どのように私はこれを達成することができますか?

+1

使用の参照トークンを、ユーザーのrelogsは、すべての古いトークンを取り消したとき。 – Mardoxx

+0

リファレンストークン?あなたの答えをもっと詳しく教えてください。ありがとう。 –

+0

または一例が素晴らしいでしょう。ありがとう。 –

答えて

0

私は目標を達成しました。ユーザーのログイン時にタイムスタンプを保存し、そのタイムスタンプをトークンのペイロードに追加し、セキュリティ層を追加してDBに対してJWTを検証し、タイムスタンプが一致しません。これは、誰かが必要な場合に.net Core 2.0で実装されたコードです。

コントローラー:

[HttpPost] 
    [Route("authenticate")] 
    public async Task<IActionResult> AuthenticateAsync([FromBody] UserModel user) 
    { 
     try 
     { 
      ....... 

      if (userSecurityKey != null) 
      { 
       var tokenHandler = new JwtSecurityTokenHandler(); 
       var key = Encoding.ASCII.GetBytes(_appSettings.Secret); 
       var tokenDescriptor = new SecurityTokenDescriptor 
       { 
        Subject = new ClaimsIdentity(new Claim[] 
        { 
         // This claim allows us to store information and use it without accessing the db 
         new Claim("userSecurityKey", userDeserialized.SecurityKey.ToString()), 
         new Claim("timeStamp",timeStamp), 
         new Claim("verificationKey",userDeserialized.VerificationKey.ToString()), 
         new Claim("userName",userDeserialized.UserName) 

        }), 
        Expires = DateTime.UtcNow.AddDays(7), 
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), 
         SecurityAlgorithms.HmacSha256Signature) 
       }; 
       var token = tokenHandler.CreateToken(tokenDescriptor); 
       var tokenString = tokenHandler.WriteToken(token); 

       // Updates timestamp for the user if there is one 
       VerificationPortalTimeStamps userTimeStamp = await _context.VerificationPortalTimeStamps.AsNoTracking().FirstOrDefaultAsync(e => e.UserName == userDeserialized.UserName); 

       if (userTimeStamp != null) 
       { 
        userTimeStamp.TimeStamp = timeStamp; 
        _context.Entry(userTimeStamp).State = EntityState.Modified; 
        await _context.SaveChangesAsync(); 
       } 
       else 
       { 
        _context.VerificationPortalTimeStamps.Add(new VerificationPortalTimeStamps { TimeStamp = timeStamp, UserName = userDeserialized.UserName }); 
        await _context.SaveChangesAsync(); 
       } 


       // return basic user info (without password) and token to store client side     
       return Json(new 
       { 
        userName = userDeserialized.UserName, 
        userSecurityKey = userDeserialized.SecurityKey, 
        token = tokenString 
       }); 
      } 

      return Unauthorized(); 

     } 
     catch (Exception) 
     { 
      return Unauthorized(); 
     } 
    } 

そして、ネットコア2.0

Startup.csとJWTベアラ認証を構成する:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider provider) 
    { 
     .................  

     app.UseAuthentication(); 

     app.UseMvc(); 

     ........... 

    } 

JWTベアラ認証設定する:

public IServiceProvider ConfigureServices(IServiceCollection services) 
    { 

     ............ 


     var key = Configuration["AppSettings:Secret"]; 

     byte[] keyAsBytes = Encoding.ASCII.GetBytes(key); 

     services.AddAuthentication(options => 
     { 
      options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 
      options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 
     }) 
      .AddJwtBearer(o => 
      { 
       o.RequireHttpsMetadata = false; 
       o.TokenValidationParameters = new TokenValidationParameters 
       { 
        ValidateIssuerSigningKey = true, 
        IssuerSigningKey = new SymmetricSecurityKey(keyAsBytes), 
        ValidateIssuer = false, 
        ValidateAudience = false, 
        ValidateLifetime = true 

       }; 

       o.Events = new JwtBearerEvents 
       { 
        OnAuthenticationFailed = context => 
        { 
         if (Configuration["AppSettings:IsGodMode"] != "true") 
          context.Response.StatusCode = 401; 


         return Task.FromResult<object>(0); 
        } 
       }; 
       o.SecurityTokenValidators.Clear(); 
       o.SecurityTokenValidators.Add(new MyTokenHandler()); 
      }); 

     services.AddMvc()     
      .AddJsonOptions(opt => 
      { 
       opt.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 
      }); 


     var provider = services.BuildServiceProvider(); 


     return provider; 
    } 

すると、次のように我々は、コントローラにカスタム検証を実装:

[Authorize] 
    [HttpGet] 
    [Route("getcandidate")] 
    public async Task<IActionResult> GetCandidateAsync() 
    { 

     try 
     { 
      ..... 

      //Get user from the claim 
      string userName = User.FindFirst("UserName").Value; 

      //Get timestamp from the db for the user 
      var currentUserTimeStamp = _context.VerificationPortalTimeStamps.AsNoTracking().FirstOrDefault(e => e.UserName == userName).TimeStamp; 

      // Compare timestamp from the claim against timestamp from the db 
      if (User.FindFirst("timeStamp").Value != currentUserTimeStamp) 
      { 
       return NotFound(); 
      } 

      ........... 

     } 
     catch (Exception) 
     { 
      return NotFound(); 
     } 
    } 
関連する問題