Twitter-Autorisierung oder wie man einen Tag mit der STTwitter-Bibliothek tötet

    Vorwort


    Einen Tag zu töten ist real, vor allem angesichts der schnellsten Twitter-Autorisierung im Vergleich zu beispielsweise demselben Facebook.
    Zum Vergleich der Algorithmus zur Erlangung der Autorisierung:

    twitter
    Erhält Token -> Ich benutze dieses Token, wir gehen zur Anmeldeseite -> Wir warten auf die Benutzerautorisierung und wir erhalten ein neues Token durch callback_url -> tauschen das Token gegen ein geheimes Token.

    facebook
    Wir öffnen die Facebook-Anmeldeseite mit dem Parameter calback_url und weiteren Optionen -> wir warten auf die Autorisierung und erhalten beim Rückruf ein geheimes Token, das verwendet werden kann.

    Ich behaupte nicht, es gibt ein SDK aus beiden sozialen Netzwerken, es gibt integrierte Datensätze, aber ich musste diese bestimmte Autorisierungsmethode implementieren. Weil andere schon ziemlich gut implementiert sind und es viele Bibliotheken gibt. Was tun, wenn die integrierten Datensätze nicht aktiviert oder deaktiviert wurden? Erzwingen Sie den Benutzer nicht, die Einstellungen aufzurufen. Während er krabbelt, kann er die Anwendung vergessen. Deshalb habe ich mich hingesetzt, um ein Login via Web für Facebook und Twitter zu entwickeln.

    Aber ich wollte speziell über Twitter sprechen, weil Twitter, wie ich oben sagte, im Vergleich zu anderen sozialen Netzwerken, die oAuth1 / 2 anbieten, nur eine riesige Menge an Fallen aufweist

    Und so fuhren sie. Für die Entwicklung habe ich mich für die STTwitter-Podbibliothek entschieden, weil ich mich nicht um das Schreiben von Saffern kümmern wollte (oh ja, für oauth 1, wenn plötzlich jemand nicht mehr alle Parameter des Anforderungsheaders prüfen muss, für die ich persönlich zu faul war). Ich muss sagen, dass die Bibliothek überraschend gut ist, aber es gibt keine Dokumentation dafür (weshalb ich mich entschlossen habe, meine Entscheidung zu veröffentlichen). Ansonsten ist alles Standard.

    Schritt 1 mit 2


    Der erste Schritt besteht darin, das erste Token zu erhalten, was im Allgemeinen nicht klar ist, warum es benötigt wird. Na gut, keine Einwände gegen das System. Alles ist hier einfach, Sie müssen die Autorisierung in der Postanforderung entsprechend den Anwendungsdaten (API-Schlüssel) und Prüfsummen senden.
    Ein wenig voraus: Mit dem empfangenen Token müssen wir einen Link erstellen, über den wir den Benutzer senden. Um den Benutzer nicht zu verlieren (um ihn daran zu hindern, die Anwendung zu verlassen), könnte man es ganz einfach tun: die Safari öffnen und dann callback_url und benutzerdefinierte URL-Schemata für die Anwendung (zum Beispiel myappscheme: // parseresult), um zur Anwendung zurückzukehren und die von Twitter übertragenen Parameter zu zappen. Und jetzt ist er die erste Falle - Twitter erlaubt es nicht, benutzerdefinierte URL-Schemata zu registrieren. Aus diesem Grund ist es unmöglich, mit einem solchen Schema zur Anwendung zurückzukehren. Wie zu sein Sie müssen eine benutzerdefinierte UIWebView erstellen und sich mit der WebView-Delegate-Methode erkälten: shouldStartLoadWithRequest: Abfangen und Überprüfen der Download-Links unserer UIWebView. Jetzt muss noch eine Art unrealistische Domain zurückgerufen werden (die sowieso nicht geladen wird,getmetothewounderlandandfeedmewitharainbownearpinkunicorns.com
    Sobald die Methode feststellt, dass die Webansicht den Befehl zum Laden dieser Domain erhalten hat, beenden wir ihre Arbeit und analysieren die Parameter für das Token.
    Ich habe die ganze Logik für den Zugriff auf die STT-Bibliothek in getrennten Klassen, ich denke, es wird klar sein, dass ich, wenn ich daher nicht betone, woher ich kommen werde, umso mehr, je detaillierter ich schreibe.
    Mit der STTwitter-Bibliothek geht das ganz einfach:

    Sofort träge Initialisierung, die ich von einem verrückten alten Mann aus Senford gelernt habe: D (wer weiß, dass er es verstehen wird). Ich verzichte auf zusätzliche Hülsen wie die Überprüfung der internen Buchhaltung im System usw.

    // api и oauth - сильные публичные свойства класса twitterEngine
    -(STTwitterOAuth *)oauth {
        if (!_oauth) {
            _oauth = [STTwitterOAuth twitterOAuthWithConsumerName:@"APP_NAME" consumerKey:TWI_API_KEY consumerSecret:TWI_API_SECREET];
        }
        return _oauth;
    }
    -(STTwitterAPI *)api {
        if (!_api) {
            if ([twitterEngine isAuthorized]) {
                NSLog(@"Full access account");
                _api = [STTwitterAPI twitterAPIWithOAuthConsumerKey:TWI_API_KEY consumerSecret:TWI_API_SECREET oauthToken:[[NSUserDefaults standardUserDefaults] valueForKey:TWI_STORE_AUTH_TOKEN] oauthTokenSecret:[[NSUserDefaults standardUserDefaults] valueForKey:TWI_STORE_AUTH_SECRET]];
            } else {
                NSLog(@"App only client");
                _api = [STTwitterAPI twitterAPIAppOnlyWithConsumerName:IN_APP_NAME consumerKey:TWI_API_KEY consumerSecret:TWI_API_SECREET];
            }
        }
        return _api;
    }
    


    Ein bisschen Controller:

    - (IBAction)loinTwitterButtonClicked:(id)sender {
        twitter = [twitterEngine new]; // twitterEngine мой класс для работы со всеми внешними средствами с twitter
        if ([twitterEngine isAuthorized]) {
            // handling authorized
        } else {
            twitter.delegate = self;
            [twitter sendRequestToken];
        }
    }
    


    Note:

    -(void)sendRequestToken
    {
        [self.oauth postTokenRequest:^(NSURL *url, NSString *oauthToken) {
            [self.delegate openWebViewWithUrl:url]; // простейший протокол передачи полученного url для загрузки в UIWebVew
        } oauthCallback:@"http://getmetothewounderlandandfeedmewitharainbownearpinkunicorns.com" errorBlock:^(NSError *error) {
            // handling error
        }];
    }
    


    Und wieder der Controller (hier die Protokollmethode und der Delegat von UIWebView, der die geladenen URLs abfängt

    -(void) openWebViewWithUrl:(NSURL *)url
    {
        // Если не задать размер за минусом статус бара браузер будет коряво накладываться на часы/батарейку/оператора
        UIWebView *browser = [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [browser loadRequest:request];
        [browser setDelegate:self];
        [self.view addSubview:browser];
    }
    -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        NSURL *url = [request URL];
        NSLog(@"Loading URL: %@", [url absoluteString]);
        if ([[url host] isEqualToString:@"getmetothewounderlandandfeedmewitharainbownearpinkunicorns.com"]) {
            [webView removeFromSuperview]; // Удаляем себя за не надобностью
            NSDictionary *params = [twitterEngine parseURLToParams:url];
            [twitter sendAccessToken:[params objectForKey:@"oauth_verifier"]]; // это и есть прямой выход на ШАГ 3 и обмен токена на сикрет.
            return NO; // если возвращаем NO то браузер просто не будет загружать эту ссылку, но параметры мы уже получили.
        }
        return YES;
    }
    


    Schritt 3


    Und die letzte Kampagne. Um die STT-Bibliothek zu diesem Thema zu studieren (der letzte Schritt), habe ich die meiste Zeit getötet und die Lösung stellte sich als ein paar Zeilen heraus. Aber wie ich wollte, habe ich die Hauptsache vermieden, mit der Prüfsumme rumgespielt und alles mit den Headern verbunden. Ich möchte auch darauf hinweisen, dass der Austausch des oauth_verifier-Tokens aufgrund der Langeweile von oAuth1 von Twitter nicht über den Header (!!!) erfolgt, wie in den vorherigen Schritten, sondern über den Hauptteil der POST-Anforderung. Hier hat STT einen Stock ins Rad gesteckt. Wie sich herausstellte, verfügt STT nicht über ein direktes Tool zum Durcharbeiten des von mir ausgewählten Autorisierungsschemas, dh es verfügt nicht über eine Methode zum Austauschen von oauth_verifier gegen oauth_token_secret. Ich musste tiefer gehen und sehr tiefe Methoden von Superklassen anwenden, die im Wesentlichen fast eine einfache Systemmethode des Sendens waren. Ein bisschen zurücktreten - ich kenne das http-Protokoll, ich weiß wie, Aber ich hatte genug Zeit, um mich mit Sockets zu beschäftigen, damit ich eine so einfache Arbeit mit Protokollen hasse. Es ist mir näher, wenn Sie die Programmierung auf mittlerer Ebene sagen können (keine Benutzeroberfläche, aber keine direkten Protokolle). Aber es gab kein Zurück und ich war bereit, meine zusätzliche Methode zu schreiben, die den Token-Austausch implementiert. Gott untersucht den Code eines anderen und fügt ihn sogar hinzu. Für mich ist dies ein wahrer Albtraum, schon allein deshalb, weil ich es nicht war, der ihn geschrieben hat. Aber es gab keinen Weg ... Als Freund bemerkte ich eine bekannte Zeitvariable @ "oauth_verifier" und begann sofort, die Methode zu studieren, bei der es bemerkt wurde. Eigentlich weiß ich immer noch nicht, warum ich die Suche mit diesem Schlüssel nicht erraten habe. Ich würde ein paar Stunden sparen. Es ist mir näher, wenn Sie die Programmierung auf mittlerer Ebene sagen können (keine Benutzeroberfläche, aber keine direkten Protokolle). Aber es gab kein Zurück und ich war bereit, meine zusätzliche Methode zu schreiben, die den Token-Austausch implementiert. Gott untersucht den Code eines anderen und fügt ihn sogar hinzu. Für mich ist dies ein wahrer Albtraum, schon allein deshalb, weil ich es nicht war, der ihn geschrieben hat. Aber es gab keinen Weg ... Als Freund bemerkte ich eine bekannte Zeitvariable @ "oauth_verifier" und begann sofort, die Methode zu studieren, bei der es bemerkt wurde. Eigentlich weiß ich immer noch nicht, warum ich die Suche mit diesem Schlüssel nicht erraten habe. Ich würde ein paar Stunden sparen. Es ist mir näher, wenn Sie die Programmierung auf mittlerer Ebene sagen können (keine Benutzeroberfläche, aber keine direkten Protokolle). Aber es gab kein Zurück und ich war bereit, meine zusätzliche Methode zu schreiben, die den Token-Austausch implementiert. Gott untersucht den Code eines anderen und fügt ihn sogar hinzu. Für mich ist dies ein wahrer Albtraum, schon allein deshalb, weil ich es nicht war, der ihn geschrieben hat. Aber es gab keinen Weg ... Als Freund bemerkte ich eine bekannte Zeitvariable @ "oauth_verifier" und begann sofort, die Methode zu studieren, bei der es bemerkt wurde. Eigentlich weiß ich immer noch nicht, warum ich die Suche mit diesem Schlüssel nicht erraten habe. Ich würde ein paar Stunden sparen. Aber es gab keinen Weg ... Als Freund bemerkte ich eine bekannte Zeitvariable @ "oauth_verifier" und begann sofort, die Methode zu studieren, bei der es bemerkt wurde. Eigentlich weiß ich immer noch nicht, warum ich die Suche mit diesem Schlüssel nicht erraten habe. Ich würde ein paar Stunden sparen. Aber es gab keinen Weg ... Als Freund bemerkte ich eine bekannte Zeitvariable @ "oauth_verifier" und begann sofort, die Methode zu studieren, bei der es bemerkt wurde. Eigentlich weiß ich immer noch nicht, warum ich die Suche mit diesem Schlüssel nicht erraten habe. Ich würde ein paar Stunden sparen.
    Was sich herausstellte: Auf Twitter gibt es eine PIN-Autorisierung. Das Schema ist ähnlich, aber es ist nur für Anwendungen implementiert, in denen ich keinen Rückruf tätigen und dadurch ein Token für den Austausch erhalten kann. Tatsächlich ist die PIN in diesem Schema ein vereinfachtes Token (verdammt noch mal, merken Sie sich die 8 Ziffern von der Site und geben Sie sie in die Anwendung ein?). Und da ich das Autorisierungsschema nie per PIN studiert habe (und es trotzdem in zwei Absätzen sogar in der Twitter-Wissensdatenbank dokumentiert ist), wusste ich nicht, dass sie einen Mechanismus haben. Glücklicherweise habe ich beschlossen, meine Methode ähnlich wie

    postAccessTokenRequestWithPIN aufzurufen: successBlock: errorBlock:

    Dies ist genau die Methode der STT-Bibliothek, die im Wesentlichen das implementierte, was ich brauchte. Nach ein paar Tastenanschlägen erhalten wir die letzte Methode der twitterEngine-Klasse, die den Austausch eines Tokens gegen ein geheimes Token implementiert und zur späteren Wiederherstellung in eine Tasche schreibt:

    -(void)sendAccessToken:(NSString *)oauth_verifier
    {
        [self.oauth postAccessTokenRequestWithPIN:oauth_verifier successBlock:^(NSString *oauthToken, NSString *oauthTokenSecret, NSString *userID, NSString *screenName) {
            [[NSUserDefaults standardUserDefaults] setObject:oauthToken forKey:TWI_STORE_AUTH_TOKEN];
            [[NSUserDefaults standardUserDefaults] setObject:oauthTokenSecret forKey:TWI_STORE_AUTH_SECRET];
            [[NSUserDefaults standardUserDefaults] synchronize];
        } errorBlock:^(NSError *error) {
            // handling error
        }];
    


    Fazit


    Im Grunde alles. Weiterhin lag die Arbeit darin, die interne Aufzeichnung im Telefon zu überprüfen, was STT im Wesentlichen direkt während der Implementierung tun kann. Wenn Sie darüber nachdenken, wie Sie diese Lösung verbessern können, ist es interessant zuzuhören. Außerdem neige ich als iOS-Entwickler meiner Natur nach dazu, Protokolle und Beobachtungen zu missbrauchen. Ich mag sie wirklich.

    Jetzt auch beliebt: