2015-05-30 14 views
5

Jestem wykonawczych OAuth przez Java z folowing sekwencji:Twitter OAuth parametr nieprawidłowy oauth_verifier

1) Wysyłanie https POST: //api.twitter.com/oauth/request_token (z zwrotnego) Twitter reponse zawiera oauth_token, oauth_token_secret i oauth_callback_confirmed = true

2) Przekierowanie na https: //api.twitter.com/oauth/authenticate oauth_token = {oauth_token od poprzedniej odpowiedzi z Twittera}

wydaje 3) Twitter formularz logowania, klikam na przycisk "zaloguj się".

4) przekierowuje Twittera {callback_url oauth_token} = {token równa token z oauth/request_token reakcji} & oauth_verifier = {weryfikatora}

5) https POST: //api.twitter.com/oauth/access_token z OAuth nagłówku zawiera oauth_token, treść wiadomości zawiera oauth_verifier = {zwrócony weryfikatora}

6) Twitter odpowiedź = błąd przetwarzania żądania OAuth: Nieprawidłowy parametr oauth_verifier

Co jest nie tak z oauth_verifier?

Obliczenie metoda podpis:

private static String computeSignature(String baseString, String keyString) throws GeneralSecurityException, UnsupportedEncodingException { 
     SecretKey secretKey = null; 

     byte[] keyBytes = keyString.getBytes(); 
     secretKey = new SecretKeySpec(keyBytes, "HmacSHA1"); 

     Mac mac = Mac.getInstance("HmacSHA1"); 
     mac.init(secretKey); 

     byte[] text = baseString.getBytes(); 

     return new String(Base64.encodeBase64(mac.doFinal(text))).trim(); 
    } 

Kod pierwsze żądanie:

String oauth_signature_method = "HMAC-SHA1"; 

    // generate any fairly random alphanumeric string as the "nonce". 
    String uuid_string = UUID.randomUUID().toString(); 
    uuid_string = uuid_string.replaceAll("-", ""); 
    String oauth_nonce = uuid_string; 

    // get the timestamp 
    Calendar tempcal = Calendar.getInstance(); 
    long ts = tempcal.getTimeInMillis(); 
    String oauth_timestamp = (new Long(ts/1000)).toString(); 
    String parameter_string = "oauth_callback=" + OauthConstants.TWITTER_OAUTH_CALLBACK 
      + "&oauth_consumer_key=" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
      + "&oauth_nonce=" + oauth_nonce + "&oauth_signature_method=" 
      + oauth_signature_method + "&oauth_timestamp=" + oauth_timestamp + "&oauth_version=1.0"; 
    String signature_base_string = get_or_post + "&" + encode(twitter_endpoint) + "&" + encode(parameter_string); 
    String oauth_signature = ""; 

    try { 
     oauth_signature = computeSignature(signature_base_string, OauthConstants.TWITTER_OAUTH_CONSUMER_SECRET + "&"); 
    } catch (GeneralSecurityException | UnsupportedEncodingException e) { 
     ...} 

String twitter_endpoint = "https://api.twitter.com/oauth/request_token"; 
String authorization_header_string = "OAuth oauth_callback=\"" + OauthConstants.TWITTER_OAUTH_CALLBACK 
       + "\",oauth_consumer_key=\"" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
       + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + oauth_timestamp 
       + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_version=\"1.0\",oauth_signature=\"" 
       + encode(oauth_signature) + "\""; 

// Apache httpcore 4.4.1 
HttpProcessor httpproc = HttpProcessorBuilder.create() 
       .add(new RequestContent()) 
       .add(new RequestTargetHost()) 
       .add(new RequestConnControl()) 
       .add(new RequestUserAgent("ApacheHttp/1.1")) 
       .add(new RequestExpectContinue(true)).build(); 

     HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); 
     HttpCoreContext context = HttpCoreContext.create(); 
     HttpHost host = new HttpHost(twitter_endpoint_host, 443); 
     DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1024); 

     context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn); 
     context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, host); 

try { 
       // initialize the HTTPS connection 
       SSLContext sslcontext = SSLContext.getInstance("TLS"); 
       sslcontext.init(null, null, null); 
       SSLSocketFactory ssf = sslcontext.getSocketFactory(); 
       Socket socket = ssf.createSocket(); 
       socket.connect(new InetSocketAddress(host.getHostName(), host.getPort()), 0); 
       conn.bind(socket); 

       BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest("POST", twitter_endpoint_path, HttpVersion.HTTP_1_1); 
       request2.setEntity(new StringEntity("", "UTF-8")); 
       request2.addHeader("Authorization", authorization_header_string); 
       httpexecutor.preProcess(request2, httpproc, context); 
       HttpResponse response2 = httpexecutor.execute(request2, conn, context); 
       httpexecutor.postProcess(response2, httpproc, context); 
} catch(Exception e) {} ... 

Kod drugiego żądania (przekierowanie https oauth/uwierzytelnienia)

public JSONObject getTwitterAuthorizationCodeFromRequestToken(String oauth_token) { 
... 
     String twitter_endpoint = "https://api.twitter.com/oauth/authenticate"; 

     ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); 
     try { 
      FacesContext.getCurrentInstance().getExternalContext().redirect(twitter_endpoint + "?oauth_token=" + encode(oauth_token)); 
     } catch (IOException ex) {...} 
... 
    } 

Kod 3 życzenie (POST oauth/access_token)

public JSONObject getTwitterAccessTokenFromAuthorizationCode(String verifier_or_pin, String oauth_token) { 
    ... 
String oauth_signature_method = "HMAC-SHA1"; 

    // generate any fairly random alphanumeric string as the "nonce". Nonce = Number used ONCE. 
    String uuid_string = UUID.randomUUID().toString(); 
    uuid_string = uuid_string.replaceAll("-", ""); 
    String oauth_nonce = uuid_string; 

    Calendar tempcal = Calendar.getInstance(); 
    long ts = tempcal.getTimeInMillis(); 
    String oauth_timestamp = (new Long(ts/1000)).toString(); 

    // the parameter string must be in alphabetical order 
    String parameter_string = "oauth_consumer_key=" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
          + "&oauth_nonce=" + oauth_nonce + "&oauth_signature_method=" + oauth_signature_method 
          + "&oauth_timestamp=" + oauth_timestamp + "&oauth_token=" + encode(oauth_token) + "&oauth_version=1.0"; 

    String signature_base_string = get_or_post + "&" + encode(twitter_endpoint) + "&" + encode(parameter_string); 

    String oauth_signature = ""; 
    try { 
     oauth_signature = computeSignature(signature_base_string, OauthConstants.TWITTER_OAUTH_CONSUMER_SECRET + "&"); 
    } catch (GeneralSecurityException | UnsupportedEncodingException e) { 
     ... 
    } 

    String authorization_header_string = "OAuth oauth_consumer_key=\"" + OauthConstants.TWITTER_OAUTH_CONSUMER_KEY 
               + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + oauth_timestamp 
               + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_version=\"1.0\",oauth_signature=\"" 
               + encode(oauth_signature) + "\",oauth_token=\"" + encode(oauth_token) + "\""; 

    HttpProcessor httpproc = HttpProcessorBuilder.create() 
        .add(new RequestContent()) 
        .add(new RequestTargetHost()) 
        .add(new RequestConnControl()) 
        .add(new RequestUserAgent("ApacheHttp/1.1")) 
        .add(new RequestExpectContinue(true)).build(); 

      HttpRequestExecutor httpexecutor = new HttpRequestExecutor(); 
      HttpCoreContext context = HttpCoreContext.create(); 
      HttpHost host = new HttpHost(twitter_endpoint_host, 443); 
      DefaultBHttpClientConnection conn = new DefaultBHttpClientConnection(8 * 1024); 

      context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn); 
      context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, host); 

    try { 
        SSLContext sslcontext = SSLContext.getInstance("TLS"); 
        sslcontext.init(null, null, null); 
        SSLSocketFactory ssf = sslcontext.getSocketFactory(); 
        Socket socket = ssf.createSocket(); 
        socket.connect(new InetSocketAddress(host.getHostName(), host.getPort()), 0); 
        conn.bind(socket); 

        BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest("POST", twitter_endpoint_path); 
        // Including oauth_verifier value to request body 
        request2.setEntity(new StringEntity("oauth_verifier=" + encode(verifier_or_pin), "UTF-8")); 
        request2.addHeader("Authorization", authorization_header_string); 
        httpexecutor.preProcess(request2, httpproc, context); 
        HttpResponse response2 = httpexecutor.execute(request2, conn, context); 
... 
    } 
+0

Czy możesz pokazać swój kod, aby to zrobić? –

+0

@Matthew C zaktualizowane pytanie –

+0

Masz dokładnie ten sam problem, czy znalazłeś rozwiązanie? –

Odpowiedz

2

Doświadczyłem dokładnie takiej samej sytuacji z naszą bazą kodu JavaScript. Po trudach dnia znalazłem rozwiązanie, które rozwiązało problem. To jest po prostu dodanie nagłówka "Content-Type" o wartości "application/x-www-form-urlencoded".

Mój kod był używany do poprawnej pracy, ale przestał działać w ciągu ostatnich kilku miesięcy. Domyślam się, że Twitter zmienił ostatnio implementację OAuth, co zmusza nas do wyraźnego dodania typu zawartości.

+1

Myślę, że dodaliby go do dokumentacji, gdyby tak było –

+1

Cóż, nie możemy winić Twittera, ponieważ jest on zdefiniowany w specyfikacji HTTP. http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1 – Basuke

+1

Oczywiście inżynierowie serwisu Twitter mogą być bardziej uprzejmi, ponieważ akceptowali prośbę bez typu zawartości. Jeśli komunikat o błędzie jest bardziej oczywisty, powiedz "Błąd: nagłówek Content-Type jest wymagany do obsługi żądania post z danymi.", Możemy znaleźć problem wcześniej. – Basuke