2016-07-08 10 views
5

Ich versuche, einen lokalen Java-basierten Client zu erstellen, der mit der SurveyMonkey-API interagiert.Kann OAuth 2.0 ohne Umleitungsserver verwendet werden?

SurveyMonkey benötigt ein langlebiges Zugriffstoken mit OAuth 2.0, mit dem ich nicht vertraut bin.

Ich habe googeln dies stundenlang, und ich denke, die Antwort ist nein, aber ich mag nur sicher sein:

Ist es möglich für mich einen einfachen Java-Client zu schreiben, die mit dem Survey in Wechselwirkung tritt, ohne Einrichten eines eigenen Redirect-Servers in einer Wolke?

Ich habe den Eindruck, dass mein eigener Online-Dienst obligatorisch ist, um die von OAuth 2.0 generierten Inhaber-Tokens empfangen zu können. Ist es möglich, dass SurveyMonkey Inhaber-Token nicht direkt an meinen Kunden senden kann?

Und wenn ich meine eigenen benutzerdefinierten Servlet irgendwo gesetzt war, und es als redirect_uri verwendet, dann die richtige Strömung würde wie folgt aussehen:

  1. Java-Client-Anfrage Inhaber Token von Surveymonkey, mit redirect_uri ist meine eigene benutzerdefinierte Servlet-URL.
  2. SurveyMonkey sendet Token an meine benutzerdefinierte Servlet-URL.
  3. Java-Client fragt benutzerdefinierte Servlet-URL ab, bis ein Token verfügbar ist?

Ist das korrekt?

+0

Ich weiß nicht, ob es eine Hilfe ist, aber für Google Auth ich meine Redirect-URL erhalten von: \t VerificationCodeReceiver Empfänger = new LocalServerReceiver(); Empfänger = Preconditions.checkNotNull (Empfänger); String redirectUri = receiver.getRedirectUri(); – c0der

Antwort

6

Nicht genau, der ganze Punkt des OAuth-Flusses besteht darin, dass der Benutzer (der Client, auf den Sie im Auftrag der Daten zugreifen) Ihnen die Berechtigung zum Zugriff auf seine Daten erteilen muss.

Siehe authentication instructions. Sie müssen den Benutzer auf OAuth authorise Seite senden:

https://api.surveymonkey.net/oauth/authorize?api_key<your_key>&client_id=<your_client_id>&response_type=code&redirect_uri=<your_redirect_uri> 

Diese eine Seite dem Benutzer zeigen, ihnen zu sagen, welche Teile ihres Kontos Sie fordern Zugang zu (ex ihre Erhebungen sehen, ihre Antworten sehen. etc). Sobald der Benutzer dies bestätigt, indem er auf dieser Seite auf "Autorisieren" klickt, wechselt SurveyMonkey automatisch zu dem, was Sie als Weiterleitungs-URI festgelegt haben (stellen Sie sicher, dass der von der obigen URL mit dem in den Einstellungen für Ihre App übereinstimmt) .

Also, wenn Ihre Redirect-URL https://example.com/surveymonkey/oauth ist, wird Survey die Benutzer zu dieser URL mit einem Code umleiten:

https://example.com/surveymonkey/oauth?code=<auth_code>

Sie müssen diesen Code nehmen und es dann für ein Zugriffstoken austauschen, indem eine tun POST-Anforderung an https://api.surveymonkey.net/oauth/token?api_key=<your_api_key> mit dem folgenden Beitrag params:

client_secret=<your_secret> 
code=<auth_code_you_just_got> 
redirect_uri=<same_redirect_uri_as_before> 
grant_type=authorization_code 

Dies wird einen Zugriffstoken zurückgeben, können Sie dann die Zugriffstoken verwenden, um Daten des auf das Benutzerkonto zuzugreifen. Sie geben das Zugriffstoken nicht an den Benutzer, den Sie für den Zugriff auf das Benutzerkonto verwenden möchten. Keine Abfrage oder irgendetwas anderes.

Wenn Sie nur auf Ihr eigenes Konto zugreifen, können Sie das Zugriffstoken verwenden, das auf der Seite mit den Einstellungen Ihrer App bereitgestellt wird.Andernfalls gibt es keine Möglichkeit, ein Zugriffstoken für einen Benutzer zu erhalten, ohne einen eigenen Redirect-Server einzurichten (es sei denn, alle Benutzer befinden sich in derselben Gruppe wie Sie, d. H. Mehrere Benutzer unter demselben Konto; aber ich werde nicht darauf eingehen). SurveyMonkey benötigt einen Platz, um Ihnen den Code zu senden, sobald der Benutzer autorisiert ist. Sie können nicht einfach einen anfordern.

+0

Ihr letzter Vorschlag bezüglich des Einstellungsfensters: Ich habe dies sowohl als einen Workaround versucht, aber es scheint nicht zu funktionieren. Ist es richtig, dass ich davon ausgehe, dass das "Zugriffs-Token" im Abschnitt "Meine Apps" das Bearer-Token ist, das ich für eine private App verwenden kann? – Tovi7

+1

@ Tovi7 Ja, Sie können den Inhaber verwenden, um auf dasselbe Konto des Eigentümers der App zuzugreifen. Dies kann immer verwendet werden, um auf das Konto des App-Eigentümers zuzugreifen, unabhängig davon, in welchem ​​Status sich die App befindet (abgesehen von deaktiviert). –

+0

Falls Sie interessiert sind, wird es wahrscheinlich auch eine Methode geben, um Zugangstoken für Benutzer in Ihrer Gruppe (Fall: private App) oder Ihr eigenes Konto (client_credentials grant_type) zu erhalten. Sie können die Dokumentation unter https://github.com/SurveyMonkey/public_api_docs ansehen, wenn Sie Änderungen melden möchten. –

5

Ja, es ist möglich, OAuth2 ohne eine Rückruf-URL zu verwenden. Die RFC6749 führt mehrere Flüsse ein. Die Erteilungsarten Implicit und Authorization Code erfordern eine Umleitungs-URI. Die Erteilungsart Resource Owner Password Credentials tut dies jedoch nicht.

Es gibt einen IETF-Entwurf, der versucht, einen anderen Grant-Typ für begrenzte Geräte einzuführen (https://tools.ietf.org/html/draft-ietf-oauth-device-flow), für den kein Umleitungs-URI erforderlich ist.

In jedem Fall, wenn die oben genannten Grant-Typen nicht Ihren Anforderungen entsprechen, verhindert nichts, dass Sie eine custom grant type erstellen.

2

Sie tun Notwendigkeit, etwas zu implementieren, die als redirect_uri handeln, die an anderer Stelle gehostet werden muss nicht unbedingt an als Ihr Client (wie Sie in irgendeiner Wolke sagen).

Ich bin nicht sehr vertraut mit Java und Servelets, aber wenn ich richtig annehme, wäre es etwas, das mit http://localhost:some_port umgehen könnte. In diesem Fall ist der von Ihnen beschriebene Ablauf korrekt.

Ich habe den gleichen Ablauf erfolgreich in C# implementiert. Hier ist die Klasse, die diesen Fluss implementiert. Ich hoffe, es hilft.

class OAuth2Negotiator 
{ 
    private HttpListener _listener = null; 
    private string _accessToken = null; 
    private string _errorResult = null; 
    private string _apiKey = null; 
    private string _clientSecret = null; 
    private string _redirectUri = null; 

    public OAuth2Negotiator(string apiKey, string address, string clientSecret) 
    { 
     _apiKey = apiKey; 
     _redirectUri = address.TrimEnd('/'); 
     _clientSecret = clientSecret; 

     _listener = new HttpListener(); 
     _listener.Prefixes.Add(address + "/"); 
     _listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous; 
    } 

    public string GetToken() 
    { 
     var url = string.Format(@"https://api.surveymonkey.net/oauth/authorize?redirect_uri={0}&client_id=sm_sunsoftdemo&response_type=code&api_key=svtx8maxmjmqavpavdd5sg5p", 
       HttpUtility.UrlEncode(@"http://localhost:60403")); 
     System.Diagnostics.Process.Start(url); 

     _listener.Start(); 
     AsyncContext.Run(() => ListenLoop(_listener)); 
     _listener.Stop(); 

     if (!string.IsNullOrEmpty(_errorResult)) 
      throw new Exception(_errorResult); 
     return _accessToken; 
    } 

    private async void ListenLoop(HttpListener listener) 
    { 
     while (true) 
     { 
      var context = await listener.GetContextAsync(); 
      var query = context.Request.QueryString; 
      if (context.Request.Url.ToString().EndsWith("favicon.ico")) 
      { 
       context.Response.StatusCode = (int)HttpStatusCode.NotFound; 
       context.Response.Close(); 
      } 
      else if (query != null && query.Count > 0) 
      { 
       if (!string.IsNullOrEmpty(query["code"])) 
       { 
        _accessToken = await SendCodeAsync(query["code"]); 
        break; 
       } 
       else if (!string.IsNullOrEmpty(query["error"])) 
       { 
        _errorResult = string.Format("{0}: {1}", query["error"], query["error_description"]); 
        break; 
       } 
      } 
     } 
    } 

    private async Task<string> SendCodeAsync(string code) 
    { 
     var GrantType = "authorization_code"; 
     //client_secret, code, redirect_uri and grant_type. The grant type must be set to “authorization_code” 
     var client = new HttpClient(); 
     client.BaseAddress = new Uri("https://api.surveymonkey.net"); 
     var request = new HttpRequestMessage(HttpMethod.Post, string.Format("/oauth/token?api_key={0}", _apiKey)); 

     var formData = new List<KeyValuePair<string, string>>(); 
     formData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret)); 
     formData.Add(new KeyValuePair<string, string>("code", code)); 
     formData.Add(new KeyValuePair<string, string>("redirect_uri", _redirectUri)); 
     formData.Add(new KeyValuePair<string, string>("grant_type", GrantType)); 
     formData.Add(new KeyValuePair<string, string>("client_id", "sm_sunsoftdemo")); 

     request.Content = new FormUrlEncodedContent(formData); 
     var response = await client.SendAsync(request); 
     if (!response.IsSuccessStatusCode) 
     { 
      _errorResult = string.Format("Status {0}: {1}", response.StatusCode.ToString(), response.ReasonPhrase.ToString()); 
      return null; 
     } 

     var data = await response.Content.ReadAsStringAsync(); 
     if (data == null) 
      return null; 
     Dictionary<string, string> tokenInfo = JsonConvert.DeserializeObject<Dictionary<string, string>>(data); 
     return(tokenInfo["access_token"]); 
    } 
}