2016-07-08 38 views
5

Sto provando a creare un client locale basato su Java che interagisce con l'API SurveyMonkey.È possibile utilizzare OAuth 2.0 senza un server di reindirizzamento?

SurveyMonkey richiede un token di accesso di lunga durata che utilizza OAuth 2.0, che non conosco molto bene.

Sono stato Googling questo per ore, e credo che la risposta è no, ma voglio solo essere sicuro:

E 'possibile per me scrivere un semplice client Java che interagisce con il SurveyMonkey, senza impostare il mio server di reindirizzamento in alcuni cloud?

Mi sembra di avere il mio servizio online obbligatorio per poter ricevere i token al portatore generati da OAuth 2.0. È possibile che SurveyMonkey non possa inviare token bearer direttamente al mio cliente?

E se dovessi impostare il mio servlet personalizzati da qualche parte, e usarlo come un redirect_uri, allora il flusso corretto sarebbe la seguente:

  1. Java-client richiesta portatore di token da SurveyMonkey, con redirect_uri è il mio URL di servlet personalizzato.
  2. SurveyMonkey invia token al mio URL di servlet personalizzato.
  3. Il client Java esegue il polling dell'URL del servlet personalizzato finché non è disponibile un token?

È corretto?

+0

Non so se è di alcun aiuto, ma per Google autenticazione ho il mio reindirizzamento URL: \t ricevitore VerificationCodeReceiver = new LocalServerReceiver(); receiver = Preconditions.checkNotNull (ricevitore); String redirectUri = receiver.getRedirectUri(); – c0der

risposta

6

Non esattamente, l'intero punto del flusso OAuth è che l'utente (il client a cui si accede per i dati per conto di) deve concedere l'autorizzazione per accedere ai propri dati.

Vedere authentication instructions. È necessario inviare l'utente alla pagina di OAuth autorizzare:

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

questo mostrerà una pagina per l'utente dicendo loro quali parti del proprio account si richiede l'accesso a (ex vedere le loro indagini, vedere le loro risposte,. eccetera). Una volta che l'utente l'ha approvato facendo clic su "Autorizza" su quella pagina, SurveyMonkey andrà automaticamente a quello che hai impostato come URI di reindirizzamento (assicurati che quello dall'url sopra corrisponda con quello che hai impostato nelle impostazioni per la tua app) con il codice .

Quindi, se l'URL di reindirizzamento era https://example.com/surveymonkey/oauth, SurveyMonkey reindirizza l'utente a tale URL con un codice:

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

È necessario prendere il codice e poi scambiarlo per un token di accesso facendo un richiesta POST a https://api.surveymonkey.net/oauth/token?api_key=<your_api_key> con i seguenti params pubblicare:

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

Ciò restituirà un token di accesso, è possibile quindi utilizzare tale token di accesso per accedere ai dati sul conto dell'utente. Non si fornisce il token di accesso all'utente che deve essere utilizzato per accedere all'account dell'utente. Non c'è bisogno di sondaggi o altro.

Se si sta solo accedendo al proprio account, è possibile utilizzare il token di accesso fornito nella pagina delle impostazioni della propria app.Altrimenti non c'è modo di ottenere un token di accesso per un utente senza impostare il proprio server di reindirizzamento (a meno che tutti gli utenti non siano nello stesso gruppo come te, cioè più utenti con lo stesso account, ma io non ci entrerò). SurveyMonkey ha bisogno di un posto dove inviare il codice una volta che l'utente lo autorizza, non puoi semplicemente richiederne uno.

+0

L'ultimo suggerimento, relativo al pannello delle impostazioni: ho provato questo e una soluzione alternativa, ma non sembra funzionare. È corretto presumere che il "token di accesso" nella sezione "Le mie app" sia il token al portatore che posso utilizzare per un'app privata? – Tovi7

+1

@ Tovi7 sì, puoi usarlo nel portatore per accedere allo stesso account del proprietario dell'app. Questo può sempre essere utilizzato per accedere all'account del proprietario dell'app, indipendentemente dallo stato in cui si trova l'app (oltre a disabilitare). –

+0

Inoltre, nel caso siate interessati, probabilmente vi sarà un metodo per ottenere token di accesso per gli utenti nel vostro gruppo (caso: app privata) o il vostro account (client_credentials grant_type). Puoi guardare i documenti su: https://github.com/SurveyMonkey/public_api_docs se sei interessato ad essere informato delle modifiche. –

5

Sì, è possibile utilizzare OAuth2 senza un URL di richiamata. RFC6749 introduce diversi flussi. I tipi di sovvenzione Implicit e Authorization Code richiedono un URI di reindirizzamento. Tuttavia il tipo di sovvenzione Resource Owner Password Credentials non lo fa.

C'è una bozza IETF che tenta di introdurre un altro tipo di concessione per dispositivi limitati (https://tools.ietf.org/html/draft-ietf-oauth-device-flow) che non richiede alcun URI di reindirizzamento.

In ogni caso, se i tipi di sovvenzione sopra indicati non si adattano alle tue esigenze, nulla ti impedisce di creare un custom grant type.

2

È do necessario implementare qualcosa che fungerà da redirect_uri, che non deve necessariamente essere ospitato da qualche altra parte del client (come si dice, in alcuni cloud).

Non ho molta familiarità con Java e Servelet, ma se presumo correttamente, sarebbe qualcosa che potrebbe gestire http://localhost:some_port. In tal caso, il flusso che descrivi è corretto.

Ho implementato correttamente lo stesso flusso in C#. Ecco la classe che implementa quel flusso. Spero possa essere d'aiuto.

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"]); 
    } 
}