6

Od trzech dni walę głową w ścianę, próbując zmusić to do działania.Serwer Google OAuth 2.0 na serwer: Złe żądanie

POST /oauth2/v3/token HTTP/1.1 
Host: www.googleapis.com 
Content-length: 495 
Content-type: application/x-www-form-urlencoded 
Authorization: Bearer ya29.cgEcY6meBrvaH6oe0nD_PtsFyMVqskiUYi7iJxapKHeEgPoIw8gMt0BJdIvRn1MfcEgzTS3_gTwI1w 
grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI5MDgyOTgxNjA1NTktc2R1bGFpbWhsaGpxOTY5M2s1Z2E4c25pZjhh%0D%0ANzhlZ3BAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0%0D%0AdHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvYW5hbHl0aWNzLnJlYWRvbmx5%0D%0AIiwiYXVkIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL3Rv%0D%0Aa2VuIiwiZXhwIjoxNDMxNTE0MDUyLCJpYXQiOjE0MzE1MTEwNTJ9.[Cert] 

HTTP/1.1 400 Bad Request 
Content-length: 67 
X-xss-protection: 1; mode=block 
X-content-type-options: nosniff 
Expires: Wed, 13 May 2015 10:08:00 GMT 
Vary: Origin,X-Origin 
Server: GSE 
Cache-control: private, max-age=0 
Date: Wed, 13 May 2015 10:08:00 GMT 
X-frame-options: SAMEORIGIN 
Content-type: application/json; charset=UTF-8 
{ 
    "error_description": "Bad Request", 
    "error": "invalid_grant" 
} 

Tak, tworzę to w PL/SQL. Oracle 12c. Udało mi się ustawić nagłówek JWT i zestaw oświadczeń JWT tak, aby generowały dane wyjściowe identyczne z dokumentacją google. Kiedy tworzę certyfikat, wydaje mi się, że wystąpił problem.

  1. Czy potrzebne "[----- POCZĄTEK PRYWATNEJ KLUCZ -----" i ----- END KLUCZEM PRYWATNYM ----- \ n] w ramach SHA 256 szyfrowania. Czy powinienem zrobić cokolwiek z "nowymi liniami"? \ n Czy powinienem go otaczać nawiasami?

  2. W którym miejscu mam kodować URL?

  3. Czy kod w poniższym przykładzie wystarczające do szyfrowania ?: http://jastraub.blogspot.co.uk/2009/07/hmacsha256-in-plsql.html

  4. mam dołączony funkcją poniżej, aby sprawdzić, czy można zidentyfikować żadnych problemów?

Dzięki za pomoc!

FUNCTION get_JWT (p_token_id ga_app_user.ID_TOKEN%TYPE) 
    RETURN VARCHAR2 
    IS 
    --Plain text 
    baseJWTheader VARCHAR2 (20000); 
    baseclaimSet VARCHAR2 (20000); 
    baseSigKey  VARCHAR2 (20000); 

    --Seconds 

    sysSeconds  NUMBER; 

    --Base64 Encoded 
    JWTheader  VARCHAR2 (20000); 
    claimSet  VARCHAR2 (20000); 
    sigKey   VARCHAR2 (20000); 
    sigContent  VARCHAR2 (20000); 


    --Returned value 
    output   RAW (20000); 
    BEGIN 
    SELECT JWT_HEADER, JWT_CLAIM_SET, SIGNATURE 
     INTO baseJWTheader, baseclaimSet, baseSigKey 
     FROM dwman.ga_app_user au 
    WHERE AU.ID_TOKEN = p_token_id; 

    --DBMS_OUTPUT.PUT_LINE ('Base claim Set ' || baseclaimSet); 
    JWTheader := 
    TRANSLATE (
     UTL_RAW.cast_to_varchar2 (
      UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (baseJWTheader))), 
     '+/', 
     '-_'); 

    SELECT ( SYSDATE 
      - TO_DATE ('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) 
     * 24 
     * 60 
     * 60 
    INTO sysSeconds 
    FROM DUAL; 

    baseclaimSet := 
    REPLACE (baseclaimSet, '#EXPIRE#', ROUND (sysSeconds + 3000)); 
    baseclaimSet := REPLACE (baseclaimSet, '#START#', ROUND (sysSeconds)); 

    --DBMS_OUTPUT.PUT_LINE ('Claim Set ' || baseclaimSet); 

    claimSet := UTL_RAW.cast_to_varchar2 (
      UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (baseclaimSet))); 

    sigKey := baseSigKey; 

    sigContent := JWTheader || '.' || claimSet; 

    --DBMS_OUTPUT.PUT_LINE('Sig Content '||sigContent); 

    sigContent := REPLACE (sigContent, CHR (10), ''); 
    sigContent := REPLACE (sigContent, CHR (13), ''); 
    /* 
    FOR V_TR in 1..length(sigContent) 
    LOOP 
    DBMS_OUTPUT.PUT_LINE (substr(sigContent,V_TR,1)||'='||to_char(ASCII(substr(sigContent,V_TR,1)))); 

    END LOOP; 
    */  
    sigContent := 
     sigContent 
    || '.' 
    || google_signature (sigContent, sigKey); 
    RETURN UTL_URL.ESCAPE(sigContent, TRUE, 'UTF-8'); 
END get_JWT; 
+0

Co dokładnie próbujesz zrobić? invalid_grant oznacza zwykle, że coś jest nie tak z czasem. – DaImTo

+0

Dzięki za komentarz. Próbuję połączyć się z danymi googleAnalytics, aby przenieść je do bazy danych. Mam następujący kod: https://developers.google.com/identity/protocols/OAuth2ServiceAccount w sekcji HTTP/Odpoczynek. Jestem blisko pisania tego procesu ETL w java zamiast, ale nie myślałem, że to będzie tak samo jak opodatkowanie. – Fudztown

+0

i czy robisz to w PL/SQL? lub czy powinienem powiedzieć, że próbujesz to zrobić bezpośrednio w PL/SQL? – DaImTo

Odpowiedz

1

fragmentu kodu może być tylko część tego, co zrobiłeś, ale wydawało się, że brakuje dużo kroków wymaganych przez Google OAuth połączyć.

można uzyskać więcej szczegółów na temat tego, co te kroki są patrząc pod tym adresem URL: https://developers.google.com/accounts/docs/OAuth2WebServer#offline

Dla pozostałej części tej odpowiedzi, opisałem moje własne doświadczenia, robiąc coś podobnego (pobieranie danych z GA, i przesłanie go do bazy danych za pomocą instrukcji SQL).

Zacznij od uzyskania klucza konsumenta i konsumenta dla swojego projektu Google. Musisz mieć adres URL, na który Google może przekierować, zarówno gdy poprosisz o klucz klienta, ale także podasz Google podczas połączeń OAuth. Muszą się zgadzać.

Następnym krokiem jest wysłanie żądania GET do Google. Oto przykład w języku C#, który można zbudować za pomocą łączenia ciągów SQL.

String URL_AUTH_FIRST = "https://accounts.google.com/o/oauth2/auth"; 
String URL_TOKEN_ENDPOINT_SECOND = "https://accounts.google.com/o/oauth2/token"; 
String url = String.Format(
    "{0}?client_id={1}&redirect_uri={2}&access_type=offline&scope={3}&response_type=code&state={4}&approval_prompt=force", 
     URL_AUTH_FIRST,_consumerKey_web_app,redir_url,scope,state); 

Aby to zrobić, musisz mieć wbudowaną przeglądarkę. Google.com przekieruje tę przeglądarkę do strony, która jest pod ich kontrolą, aby użytkownik mógł się zalogować lub odmówić autoryzacji aplikacji. Gdy Google ma potrzebne informacje, przekierowuje z powrotem do wbudowanej przeglądarki. Możesz wykonać niektóre kroki, używając funkcji kopiuj/wklej w swojej przeglądarce, ale w pewnym momencie (opisanym poniżej) musisz POST zwrócić niektóre dane, których nie wiedziałbym, jeśli możesz to zrobić z poziomu aplikacji przeglądarki.

Google odpowie, przekierowując przeglądarkę do adresu URL. Adres URL zawiera dane. Musisz przeanalizować parametry na URL i poszukać parametru "code". Jeśli otrzymasz adres URL z parametrem "code", musisz POST formatować w pewnym formacie z powrotem do Google.

WebClient client = get_WebClient(); // proprietary to include things like proxy info 
try { 
    NameValueCollection values = new NameValueCollection(); 
    values.Add("client_id", _consumerKey_web_app); 
    values.Add("client_secret", _consumerSecret_web_app_offline); 
    values.Add("grant_type", "authorization_code"); 
    values.Add("redirect_uri", URL_GOOGLE_REDIRECTS_TO_THIS_URL_AFTER_URL_AUTH); 
    values.Add("code", authorization_code); 
    Byte[] responseBytes = client.UploadValues(URL_TOKEN_ENDPOINT_SECOND, values); 
} 

Google zwróci "responseBytes", które byłyby json sformatowany ciąg, przypominające:

{ 
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg", 
        "expires_in":3920, 
        "token_type":"Bearer", 
        "refresh_token":"1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ" 
       } 

access_token zostanie dołączona do REST API.

Możesz dostarczyć zapytanie GA za pośrednictwem REST API, odzyskać dane i przesłać je do bazy danych za pomocą instrukcji SQL. Tak robi moja aplikacja.

Możesz zapisać ten refresh_token i dostarczyć go w przyszłych połączeniach. Rzeczywiście, cała ta sekwencja musi być wykonana za pomocą przeglądarki lub kontrolki przeglądarki, interaktywnie z użytkownikiem logującym się. Po tym jak skończyłeś, a otrzymałeś refresh_token, twój SQL może użyć i ponownie użyć refresh_token w zasadzie w-zdecydowanie , przynajmniej do czasu zmiany hasła użytkownika.

Google będzie również regularnie zwracać błąd 401. To oznacza, że ​​musisz ponownie poprosić o token dostępu, publikując nowy zestaw wartości dla Google:

NameValueCollection values = new NameValueCollection(); 
        values.Add("client_id", _consumerKey_web_app); 
        values.Add("client_secret", _consumerSecret_web_app_offline); 
        values.Add("refresh_token", refresh_token); 
        values.Add("grant_type", "refresh_token"); 
        Byte[] responseBytes = client.UploadValues(URL_TOKEN_ENDPOINT_SECOND, values);