5

我正在使用asp.net身份進行web api中基於令牌的身份驗證。web api - 即使是後續請求,asp.net身份令牌也會過期

對於刷新令牌,我基於以下鏈接

我已經添加了以下兩類,並在啓動配置中提到的實現。

從UI我叫用的用戶名和密碼單獨通過API

http://domain/token

當我調用上面的API,請求直接進入方法ValidateClientAuthentication

但是在這種方法的邏輯是,我們需要發送客戶端的id和客戶端的祕密。

在用戶登錄特定用戶之前,我們如何知道這兩個?

我認爲工作流程應該是這樣的,我們需要檢查數據庫的用戶名和密碼,並生成訪問令牌和刷新令牌。

但是,我在哪裏做這個邏輯。

樣本中提到的這個系統的工作流程是什麼?

這個系統之前,我會打電話給我的應用程序的通用/登錄API,併成功驗證之後,

我會打電話的代碼,以使用戶的登錄

var userIdentity=await user.GenerateUserIdentityAsync(UserManager); 

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, userIdentity); 

在上面的代碼之後,我將從用戶身份生成訪問令牌。

我已經嘗試了很多次,下面的實現和厭倦了流程。

幫我看看這裏提到的邏輯和流程。

SimpleAuthorizationServerProvider

namespace AngularJSAuthentication.API.Providers 
    { 
     public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider 
     { 
      public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
      { 

       string clientId = string.Empty; 
      string clientSecret = string.Empty; 
      Client client = null; 

      if (!context.TryGetBasicCredentials(out clientId, out clientSecret)) 
      { 
       context.TryGetFormCredentials(out clientId, out clientSecret); 
      } 

      if (context.ClientId == null) 
      { 
       //Remove the comments from the below line context.SetError, and invalidate context 
       //if you want to force sending clientId/secrects once obtain access tokens. 
       context.Validated(); 
       //context.SetError("invalid_clientId", "ClientId should be sent."); 
       return Task.FromResult<object>(null); 
      } 

      using (AuthRepository _repo = new AuthRepository()) 
      { 
       client = _repo.FindClient(context.ClientId); 
      } 

      if (client == null) 
      { 
       context.SetError("invalid_clientId", string.Format("Client '{0}' is not registered in the system.", context.ClientId)); 
       return Task.FromResult<object>(null); 
      } 

      if (client.ApplicationType == Models.ApplicationTypes.NativeConfidential) 
      { 
       if (string.IsNullOrWhiteSpace(clientSecret)) 
       { 
        context.SetError("invalid_clientId", "Client secret should be sent."); 
        return Task.FromResult<object>(null); 
       } 
       else 
       { 
        if (client.Secret != Helper.GetHash(clientSecret)) 
        { 
         context.SetError("invalid_clientId", "Client secret is invalid."); 
         return Task.FromResult<object>(null); 
        } 
       } 
      } 

      if (!client.Active) 
      { 
       context.SetError("invalid_clientId", "Client is inactive."); 
       return Task.FromResult<object>(null); 
      } 

      context.OwinContext.Set<string>("as:clientAllowedOrigin", client.AllowedOrigin); 
      context.OwinContext.Set<string>("as:clientRefreshTokenLifeTime", client.RefreshTokenLifeTime.ToString()); 

      context.Validated(); 
      return Task.FromResult<object>(null); 
     } 

     public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
     { 

      var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); 

      if (allowedOrigin == null) allowedOrigin = "*"; 

      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); 

      using (AuthRepository _repo = new AuthRepository()) 
      { 
       IdentityUser user = await _repo.FindUser(context.UserName, context.Password); 

       if (user == null) 
       { 
        context.SetError("invalid_grant", "The user name or password is incorrect."); 
        return; 
       } 
      } 

      var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
      identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); 
      identity.AddClaim(new Claim(ClaimTypes.Role, "user")); 
      identity.AddClaim(new Claim("sub", context.UserName)); 

      var props = new AuthenticationProperties(new Dictionary<string, string> 
       { 
        { 
         "as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId 
        }, 
        { 
         "userName", context.UserName 
        } 
       }); 

      var ticket = new AuthenticationTicket(identity, props); 
      context.Validated(ticket); 

     } 

     public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context) 
     { 
      var originalClient = context.Ticket.Properties.Dictionary["as:client_id"]; 
      var currentClient = context.ClientId; 

      if (originalClient != currentClient) 
      { 
       context.SetError("invalid_clientId", "Refresh token is issued to a different clientId."); 
       return Task.FromResult<object>(null); 
      } 

      // Change auth ticket for refresh token requests 
      var newIdentity = new ClaimsIdentity(context.Ticket.Identity); 

      var newClaim = newIdentity.Claims.Where(c => c.Type == "newClaim").FirstOrDefault(); 
      if (newClaim != null) 
      { 
       newIdentity.RemoveClaim(newClaim); 
      } 
      newIdentity.AddClaim(new Claim("newClaim", "newValue")); 

      var newTicket = new AuthenticationTicket(newIdentity, context.Ticket.Properties); 
      context.Validated(newTicket); 

      return Task.FromResult<object>(null); 
     } 

     public override Task TokenEndpoint(OAuthTokenEndpointContext context) 
     { 
      foreach (KeyValuePair<string, string> property in context.Properties.Dictionary) 
      { 
       context.AdditionalResponseParameters.Add(property.Key, property.Value); 
      } 

      return Task.FromResult<object>(null); 
     } 

    } 
} 

SimpleRefreshTokenProvider

namespace AngularJSAuthentication.API.Providers 
{ 
    public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider 
    { 

     public async Task CreateAsync(AuthenticationTokenCreateContext context) 
     { 
      var clientid = context.Ticket.Properties.Dictionary["as:client_id"]; 

      if (string.IsNullOrEmpty(clientid)) 
      { 
       return; 
      } 

      var refreshTokenId = Guid.NewGuid().ToString("n"); 

      using (AuthRepository _repo = new AuthRepository()) 
      { 
       var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime"); 

       var token = new RefreshToken() 
       { 
        Id = Helper.GetHash(refreshTokenId), 
        ClientId = clientid, 
        Subject = context.Ticket.Identity.Name, 
        IssuedUtc = DateTime.UtcNow, 
        ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime)) 
       }; 

       context.Ticket.Properties.IssuedUtc = token.IssuedUtc; 
       context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc; 

       token.ProtectedTicket = context.SerializeTicket(); 

       var result = await _repo.AddRefreshToken(token); 

       if (result) 
       { 
        context.SetToken(refreshTokenId); 
       } 

      } 
     } 

     public async Task ReceiveAsync(AuthenticationTokenReceiveContext context) 
     { 

      var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin"); 
      context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin }); 

      string hashedTokenId = Helper.GetHash(context.Token); 

      using (AuthRepository _repo = new AuthRepository()) 
      { 
       var refreshToken = await _repo.FindRefreshToken(hashedTokenId); 

       if (refreshToken != null) 
       { 
        //Get protectedTicket from refreshToken class 
        context.DeserializeTicket(refreshToken.ProtectedTicket); 
        var result = await _repo.RemoveRefreshToken(hashedTokenId); 
       } 
      } 
     } 

     public void Create(AuthenticationTokenCreateContext context) 
     { 
      throw new NotImplementedException(); 
     } 

     public void Receive(AuthenticationTokenReceiveContext context) 
     { 
      throw new NotImplementedException(); 
     } 
    } 
} 
+0

「如果我設置令牌過期10分鐘,...,令牌已經過期了10分鐘。「那麼,這似乎是合理的! ;-) –

+0

對於後續的請求,令牌應該過期應該延長。令牌應在10分鐘的空閒時間內過期。 –

+0

是的,我明白了。只是這句話對我來說很古怪。順便檢查一下我的答案和教程鏈接,瞭解如何使用刷新令牌擴展會話。 –

回答

1

如何使用刷新標記並將其存儲在數據庫中,像這兩個例子:

如在第一個鏈接廣泛描述的,你可以創建自己的令牌提供商實現來處理憑證更新:

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider 
{ 

    public async Task CreateAsync(AuthenticationTokenCreateContext context) 
    { 
     var clientid = context.Ticket.Properties.Dictionary["as:client_id"]; 

     if (string.IsNullOrEmpty(clientid)) 
     { 
      return; 
     } 

     var refreshTokenId = Guid.NewGuid().ToString("n"); 

     using (AuthRepository _repo = new AuthRepository()) 
     { 
      var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime"); 

      var token = new RefreshToken() 
      { 
       Id = Helper.GetHash(refreshTokenId), 
       ClientId = clientid, 
       Subject = context.Ticket.Identity.Name, 
       IssuedUtc = DateTime.UtcNow, 
       ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime)) 
      }; 

      context.Ticket.Properties.IssuedUtc = token.IssuedUtc; 
      context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc; 

      token.ProtectedTicket = context.SerializeTicket(); 

      var result = await _repo.AddRefreshToken(token); 

      if (result) 
      { 
       context.SetToken(refreshTokenId); 
      } 

     } 
    } 
} 
+0

儘管此鏈接可能回答問題,但最好在此處包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 - [來自評論](/ review/low-quality-posts/10702608) – dav

+1

@dav,是的好點。 –

+0

我已經添加了這些類並實施。我不知道這些方法是自動調用,還是需要調用這些方法。如果我需要手動呼叫,那麼我不知道何時/在哪裏打電話。 –

相關問題