2015-07-28 5 views
6

Ich habe vor kurzem Setup IdentityServer v3 und läuft wie ein Traum, aber ich habe Probleme mit der OWIN-Middleware.Refresh Tokens mit OWIN Middleware und IdentityServer v3

Ich möchte den hybriden Fluss verwenden, damit ich Token im Backend aktualisieren kann, ohne dass der Benutzer zurück zum IdentityServer umleiten muss, um alle 5 Minuten ein neues Zugriffstoken zu erhalten Lebensdauer von 1 Stunde auf dem Server).

Ich verwende die folgende Konfiguration beim Start und ich bekomme die Token in Ordnung, aber es scheint nie zu versuchen und aktualisieren Sie das Access Token, sobald es abgelaufen ist. Benötige ich irgendwo eine benutzerdefinierte Logik, um meine Token zu aktualisieren?

 app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions 
     { 
      ClientId = clientId, 
      ClientSecret = clientSecret, //Not sure what this does? 

      Authority = "https://auth.example.com", 

      RedirectUri = "http://website.example.com", 
      PostLogoutRedirectUri = "http://website.example.com", 

      ResponseType = "code id_token token", 
      Scope = "openid profile email write read offline_access", 

      SignInAsAuthenticationType = "Cookies", 

      Notifications = new OpenIdConnectAuthenticationNotifications 
      { 
       AuthorizationCodeReceived = async n => 
       { 
        // filter "protocol" claims 
        var claims = new List<Claim>(from c in n.AuthenticationTicket.Identity.Claims 
               where c.Type != "iss" && 
                 c.Type != "aud" && 
                 c.Type != "nbf" && 
                 c.Type != "exp" && 
                 c.Type != "iat" && 
                 c.Type != "nonce" && 
                 c.Type != "c_hash" && 
                 c.Type != "at_hash" 
               select c); 

        // get userinfo data 
        var userInfoClient = new UserInfoClient(
         new Uri(n.Options.Authority + "/connect/userinfo"), 
         n.ProtocolMessage.AccessToken); 

        var userInfo = await userInfoClient.GetAsync(); 
        userInfo.Claims.ToList().ForEach(ui => claims.Add(new Claim(ui.Item1, ui.Item2))); 

        // get access and refresh token 
        var tokenClient = new OAuth2Client(
         new Uri(n.Options.Authority + "/connect/token"), 
         clientId, 
         clientSecret); 

        var response = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri); 

        claims.Add(new Claim("access_token", response.AccessToken)); 
        claims.Add(new Claim("expires_at", DateTime.UtcNow.AddSeconds(response.ExpiresIn).ToLocalTime().ToString(CultureInfo.InvariantCulture))); 
        claims.Add(new Claim("refresh_token", response.RefreshToken)); 
        claims.Add(new Claim("id_token", n.ProtocolMessage.IdToken)); 

        //Does this help? 
        n.AuthenticationTicket.Properties.AllowRefresh = true; 

        n.AuthenticationTicket = new AuthenticationTicket(
         new ClaimsIdentity(
          claims.Distinct(new ClaimComparer()), 
          n.AuthenticationTicket.Identity.AuthenticationType), 
         n.AuthenticationTicket.Properties); 
       }, 

       RedirectToIdentityProvider = async n => 
       { 
        // if signing out, add the id_token_hint 
        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest) 
        { 
         var id = n.OwinContext.Authentication.User.FindFirst("id_token"); 

         if (id != null) 
         { 
          var idTokenHint = id.Value; 
          n.ProtocolMessage.IdTokenHint = idTokenHint; 
         } 
        } 
       } 
      } 
     }); 

ich auch die folgenden in meinem ApiClient (RestSharp) verwendet, die zu meiner Ressource api spricht

public class MyTokenAuthenticator : IAuthenticator 
{ 
    public void Authenticate(IRestClient client, IRestRequest request) 
    { 
     var tokenClaim = ClaimsPrincipal.Current.Claims.FirstOrDefault(c => c.Type.Equals("access_token")); 

     if (tokenClaim != null && !String.IsNullOrWhiteSpace(tokenClaim.Value)) 
      request.AddHeader("Authorization", String.Format("Bearer {0}", tokenClaim.Value)); 
    } 
} 

Antwort

1

konnte ich eine Aktualisierungs-Token bekommen und es dann einen neuen Zugang zu erhalten, verwenden Token: Ich folgte ähnlichen Logik wie Sie, um ein Token zu erhalten. ich die folgende Methode geschaffen, die ich jedes Mal, rief ich ein Token benötigt:

private static async Task CheckAndPossiblyRefreshToken(ClaimsIdentity id) 
    { 
     var clientName = "Myhybridclient"; 
     // check if the access token hasn't expired. 
     if (DateTime.Now.ToLocalTime() >= 
      (DateTime.Parse(id.FindFirst("expires_at").Value))) 
     { 
      // expired. Get a new one. 
      var tokenEndpointClient = new OAuth2Client(
       new Uri(Constants.TokenEndpoint), 
       clientName, 
       "secret"); 

      var tokenEndpointResponse = 
       await tokenEndpointClient 
       .RequestRefreshTokenAsync(id.FindFirst("refresh_token").Value); 

      if (!tokenEndpointResponse.IsError) 
      { 
       // replace the claims with the new values - this means creating a 
       // new identity!        
       var result = from claim in id.Claims 
          where claim.Type != "access_token" && claim.Type != "refresh_token" && 
            claim.Type != "expires_at" 
          select claim; 

       var claims = result.ToList(); 

       claims.Add(new Claim("access_token", tokenEndpointResponse.AccessToken)); 
       claims.Add(new Claim("expires_at", 
          DateTime.Now.AddSeconds(tokenEndpointResponse.ExpiresIn) 
          .ToLocalTime().ToString())); 
       claims.Add(new Claim("refresh_token", tokenEndpointResponse.RefreshToken)); 

       var newIdentity = new ClaimsIdentity(claims, "Cookies"); 
       var wrapper = new HttpRequestWrapper(HttpContext.Current.Request); 
       wrapper.GetOwinContext().Authentication.SignIn(newIdentity); 
      } 
      else 
      { 
       // log, ... 
       throw new Exception("An error has occurred"); 
      } 
     } 
    } 
+1

Meiner Meinung nach bis Ortszeit wartet größer oder gleich Zugriffstoken Ablaufzeit ist nicht die beste Idee. Stellen Sie sich eine Situation vor, in der diese Bedingung AccessToken nur wenige Millisekunden vor Ablauf als gültig betrachtet. Wenn Sie ein solches AccessToken an einen anderen Dienst senden, könnte es zurückgewiesen werden, da es in der Zwischenzeit abgelaufen ist. Wenn Sie den Claim "expires_at" hinzufügen, können Sie auch etwas wie den "refresh_at" Claim als Halbzeitspanne zwischen jetzt und "expires_at" hinzufügen. Eine solche Lösung würde sicherstellen, dass Access Token nicht abläuft, bevor Sie es verwenden können. – Gilmor

+0

Ich erlaube normalerweise, durch Konfiguration, ich Minute, um zu überprüfen, wenn Token abgelaufen ist: zum Beispiel, wenn das Token in weniger als 1 Minute ausläuft, werde ich fortfahren und es aktualisieren. – jahansha

Verwandte Themen