OAuth 2.0-Autorisierung für LinkedIn in Android

Lesezeit: 13 Minuten

OAuth 20 Autorisierung fur LinkedIn in Android
amalBit

Obwohl es kein Android-spezifisches SDK von linkedIn gibt (wie Facebook- und Twitter-SDK für Android). Die Einrichtung der linkedIn-Autorisierung mit Oauth 1.0 war immer noch einfach:

Aber es ist nicht dasselbe für die Autorisierung mit Oauth2.0. Nicht zu viele nützliche Bibliotheken oder Android-spezifische Beispiele. Ich habe versucht, diese zu verwenden:

Ich habe gelesen, dass Oauth 2.0 viel einfacher zu implementieren ist als 1.0. Trotzdem kann ich das nicht.

Irgendwelche Hinweise zur Implementierung von Oauth2.0 für LinkedIn in Android?

OAuth 20 Autorisierung fur LinkedIn in Android
amalBit

Oauth2.0-Authentifizierung für LinkedIN.

Schritt 1:

  • Registrieren Sie Ihre App bei linkedIn, indem Sie folgen dieses Dokument. Und holen Sie sich Ihren api_key und api_secret.

Schritt 2:

Hauptaktivität:

public class MainActivity extends Activity {

/*CONSTANT FOR THE AUTHORIZATION PROCESS*/

/****FILL THIS WITH YOUR INFORMATION*********/
//This is the public api key of our application
private static final String API_KEY = "YOUR_API_KEY";
//This is the private api key of our application
private static final String SECRET_KEY = "YOUR_API_SECRET";
//This is any string we want to use. This will be used for avoiding CSRF attacks. You can generate one here: http://strongpasswordgenerator.com/
private static final String STATE = "E3ZYKC1T6H2yP4z";
//This is the url that LinkedIn Auth process will redirect to. We can put whatever we want that starts with http:// or https:// .
//We use a made up url that we will intercept when redirecting. Avoid Uppercases. 
private static final String REDIRECT_URI = "http://com.amalbit.redirecturl";
/*********************************************/

//These are constants used for build the urls
private static final String AUTHORIZATION_URL = "https://www.linkedin.com/uas/oauth2/authorization";
private static final String ACCESS_TOKEN_URL = "https://www.linkedin.com/uas/oauth2/accessToken";
private static final String SECRET_KEY_PARAM = "client_secret";
private static final String RESPONSE_TYPE_PARAM = "response_type";
private static final String GRANT_TYPE_PARAM = "grant_type";
private static final String GRANT_TYPE = "authorization_code";
private static final String RESPONSE_TYPE_VALUE ="code";
private static final String CLIENT_ID_PARAM = "client_id";
private static final String STATE_PARAM = "state";
private static final String REDIRECT_URI_PARAM = "redirect_uri";
/*---------------------------------------*/
private static final String QUESTION_MARK = "?";
private static final String AMPERSAND = "&";
private static final String EQUALS = "=";

private WebView webView;
private ProgressDialog pd;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //get the webView from the layout
    webView = (WebView) findViewById(R.id.main_activity_web_view);

    //Request focus for the webview
    webView.requestFocus(View.FOCUS_DOWN);

    //Show a progress dialog to the user
    pd = ProgressDialog.show(this, "", this.getString(R.string.loading),true);

    //Set a custom web view client
    webView.setWebViewClient(new WebViewClient(){
          @Override
          public void onPageFinished(WebView view, String url) {
                //This method will be executed each time a page finished loading.
                //The only we do is dismiss the progressDialog, in case we are showing any.
              if(pd!=null && pd.isShowing()){
                  pd.dismiss();
              }
          }
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String authorizationUrl) {
            //This method will be called when the Auth proccess redirect to our RedirectUri.
            //We will check the url looking for our RedirectUri.
            if(authorizationUrl.startsWith(REDIRECT_URI)){
                Log.i("Authorize", "");
                Uri uri = Uri.parse(authorizationUrl);
                //We take from the url the authorizationToken and the state token. We have to check that the state token returned by the Service is the same we sent.
                //If not, that means the request may be a result of CSRF and must be rejected.
                String stateToken = uri.getQueryParameter(STATE_PARAM);
                if(stateToken==null || !stateToken.equals(STATE)){
                    Log.e("Authorize", "State token doesn't match");
                    return true;
                }

                //If the user doesn't allow authorization to our application, the authorizationToken Will be null.
                String authorizationToken = uri.getQueryParameter(RESPONSE_TYPE_VALUE);
                if(authorizationToken==null){
                    Log.i("Authorize", "The user doesn't allow authorization.");
                    return true;
                }
                Log.i("Authorize", "Auth token received: "+authorizationToken);

                //Generate URL for requesting Access Token
                String accessTokenUrl = getAccessTokenUrl(authorizationToken);
                //We make the request in a AsyncTask
                new PostRequestAsyncTask().execute(accessTokenUrl);

            }else{
                //Default behaviour
                Log.i("Authorize","Redirecting to: "+authorizationUrl);
                webView.loadUrl(authorizationUrl);
            }
            return true;
        }
    });

    //Get the authorization Url
    String authUrl = getAuthorizationUrl();
    Log.i("Authorize","Loading Auth Url: "+authUrl);
    //Load the authorization URL into the webView
    webView.loadUrl(authUrl);
}

/**
 * Method that generates the url for get the access token from the Service
 * @return Url
 */
private static String getAccessTokenUrl(String authorizationToken){
    return ACCESS_TOKEN_URL
            +QUESTION_MARK
            +GRANT_TYPE_PARAM+EQUALS+GRANT_TYPE
            +AMPERSAND
            +RESPONSE_TYPE_VALUE+EQUALS+authorizationToken
            +AMPERSAND
            +CLIENT_ID_PARAM+EQUALS+API_KEY
            +AMPERSAND
            +REDIRECT_URI_PARAM+EQUALS+REDIRECT_URI
            +AMPERSAND
            +SECRET_KEY_PARAM+EQUALS+SECRET_KEY;
}
/**
 * Method that generates the url for get the authorization token from the Service
 * @return Url
 */
private static String getAuthorizationUrl(){
    return AUTHORIZATION_URL
            +QUESTION_MARK+RESPONSE_TYPE_PARAM+EQUALS+RESPONSE_TYPE_VALUE
            +AMPERSAND+CLIENT_ID_PARAM+EQUALS+API_KEY
            +AMPERSAND+STATE_PARAM+EQUALS+STATE
            +AMPERSAND+REDIRECT_URI_PARAM+EQUALS+REDIRECT_URI;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

private class PostRequestAsyncTask extends AsyncTask<String, Void, Boolean>{

    @Override
    protected void onPreExecute(){
        pd = ProgressDialog.show(MainActivity.this, "", MainActivity.this.getString(R.string.loading),true);
    }

    @Override
    protected Boolean doInBackground(String... urls) {
        if(urls.length>0){
            String url = urls[0];
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpost = new HttpPost(url);
            try{
                HttpResponse response = httpClient.execute(httpost);
                if(response!=null){
                    //If status is OK 200
                    if(response.getStatusLine().getStatusCode()==200){
                        String result = EntityUtils.toString(response.getEntity());
                        //Convert the string result to a JSON Object
                        JSONObject resultJson = new JSONObject(result);
                        //Extract data from JSON Response
                        int expiresIn = resultJson.has("expires_in") ? resultJson.getInt("expires_in") : 0;

                        String accessToken = resultJson.has("access_token") ? resultJson.getString("access_token") : null;
                        Log.e("Tokenm", ""+accessToken);
                        if(expiresIn>0 && accessToken!=null){
                            Log.i("Authorize", "This is the access Token: "+accessToken+". It will expires in "+expiresIn+" secs");

                            //Calculate date of expiration
                            Calendar calendar = Calendar.getInstance();
                            calendar.add(Calendar.SECOND, expiresIn);
                            long expireDate = calendar.getTimeInMillis();

                            ////Store both expires in and access token in shared preferences
                            SharedPreferences preferences = MainActivity.this.getSharedPreferences("user_info", 0);
                            SharedPreferences.Editor editor = preferences.edit();
                            editor.putLong("expires", expireDate);
                            editor.putString("accessToken", accessToken);
                            editor.commit();

                            return true;
                        }
                    }
                }
            }catch(IOException e){
                Log.e("Authorize","Error Http response "+e.getLocalizedMessage());  
            }
            catch (ParseException e) {
                Log.e("Authorize","Error Parsing Http response "+e.getLocalizedMessage());
            } catch (JSONException e) {
                Log.e("Authorize","Error Parsing Http response "+e.getLocalizedMessage());
            }
        }
        return false;
    }

    @Override
    protected void onPostExecute(Boolean status){
        if(pd!=null && pd.isShowing()){
            pd.dismiss();
        }
        if(status){
            //If everything went Ok, change to another activity.
            Intent startProfileActivity = new Intent(MainActivity.this, ProfileActivity.class);
            MainActivity.this.startActivity(startProfileActivity);
        }
    }

};
}

Und das xmlLayout:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <WebView
        android:id="@+id/main_activity_web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Das Token wird in der Sharedpreference-Datei gespeichert.

Einfaches Android-Projekt-Repository hier in github.

  • Muss die Umleitungs-URL gleich sein? Kann ich eine andere URL erhalten?

    – Akshat

    13. Oktober 14 um 15:22 Uhr

  • Ich habe ein seltsames Problem, nachdem das Popup angezeigt wird, dass die Android-Tastatur angezeigt wird, aber beim Klicken auf die Buchstaben nicht funktioniert. Was? Ich kann die Anmeldeinformationen nicht eingeben.

    – Mustafa Güven

    16. Oktober 14 um 8:20 Uhr

  • Ich möchte nur erwähnen, dass Sie keine zufällige Redirect_uri mehr verwenden können: Sie müssen diejenige verwenden, die Sie im Formular „App hinzufügen“ angegeben haben, das Sie ausfüllen.

    – u3l

    13. Januar 15 um 23:12 Uhr

  • Wenn jemand etwas mehr über OAuth und STATE-Konstante lesen möchte: twobotechnologies.com/blog/2014/02/…

    – Heloisasim

    9. August 16 um 14:09 Uhr


  • Funktioniert perfekt. Danke für das Teilen

    – Satyam Gondhale

    27. Februar 21 um 19:09 Uhr

Ich habe es zum Laufen gebracht, aber es hat mich… einige Zeit gekostet.

ich folgte LinkedIn-Authentifizierung das zu verwalten.
Ich rate trotzdem dringend, diesen Link trotzdem zu lesen, da ich nicht alle Fälle in meinen Beispielen abdecke (Fehler, Fehlerbehandlung, Best Practices, Parameterverwendung, genaue Dokumentation …)

  • Zuerst benötigen Sie Ihren LinkedIn-API-Schlüssel und Ihren geheimen Schlüssel. Wenn nicht, registrieren Sie eine App auf Hier.

  • Zweitens benötigen Sie eine Aktivität in der Anwendung, die den Autorisierungscode empfangen kann. Dazu muss es in der Datei AndroidManifest.xml als durchsuchbar (von einem Browser aus startbar) festgelegt werden:

        <activity
          android:name=".ResultActivity"
          android:label="" >
          <intent-filter>
            <action android:name="android.intent.action.VIEW"/>
    
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>
          </intent-filter>
    

    Obwohl es nicht empfohlen wird, ist es möglich, ein Daten-Tag zu verwenden, um URIs mit einem benutzerdefinierten Schema abzurufen:

      <data android:scheme="oauth"/>
    
  • Danach müssen Sie den Benutzer mit einer bestimmten URL zum Autorisierungsdialogfeld von LinkedIn umleiten:

    https://www.linkedin.com/uas/oauth2/authorization?response_type=code
                                       &client_id=YOUR_API_KEY
                                       &scope=SCOPE 
                                       &state=STATE
                                       &redirect_uri=YOUR_REDIRECT_URI
    

    Sie können eine WebView verwenden, um sie direkt in Ihrer Anwendung anzuzeigen, oder sie vom System über eine Absicht wie die folgenden behandeln lassen:

    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(/* FULL URL */));
    startActivity(intent);
    

    Das einzige Problem hierbei ist, dass die API keine anderen Schemata als http oder https akzeptiert, was bedeutet, dass Sie den Intent-URI nicht einfach als Parameter „redirect_uri“ übergeben können.

    Also habe ich auf meinem Server eine Zielseite erstellt, deren einziger Zweck darin besteht, auf die Anwendung umzuleiten. Wir können uns so etwas vorstellen wie (in hässlichem PHP abkürzen) (Absichtsref.) :

    header('Location: ' . "intent:#Intent;component=your.package/.ResultActivity;S.code=" . $_GET['code'] . ";S.state=" . $_GET['state'] . ";end");
    die();
    

    Also alles klar! Jetzt die onCreate(Bundle) der ResultActivity :

    Intent intent = getIntent();
    String authorizationCode = intent.getStringExtra("code");
    

    Es gibt eine andere Möglichkeit, hier Parameter zu übergeben, wenn das Daten-Tag früher verwendet wurde.

  • Fast dort! Jetzt müssen Sie nur noch eine einfache POST-Anforderung für diese URL ausführen:

    https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code
                                        &code=AUTHORIZATION_CODE
                                        &redirect_uri=YOUR_REDIRECT_URI
                                        &client_id=YOUR_API_KEY
                                        &client_secret=YOUR_SECRET_KEY
    

    Rückkehr a JSON Objekt auf Erfolg :

    {"expires_in":5184000,"access_token":"AQXdSP_W41_UPs5ioT_t8HESyODB4FqbkJ8LrV_5mff4gPODzOYR"}

Et voilà! Sie können jetzt Ihre API-Aufrufe mit dem access_token durchführen. Vergiss es nicht speichern irgendwo, damit Sie diese Schritte nicht noch einmal durchlaufen müssen.

Ich hoffe, das war nicht zu lang zum Lesen und dass es einigen Leuten helfen kann. 🙂

  • Kann man in php auf die Landingpage verzichten?

    – amalBit

    5. März 14 um 11:26 Uhr

  • @amalBit Es gibt einige Möglichkeiten, dies zu umgehen, aber das ändert meiner Meinung nach die Natur von Oauth2. Für die Lösungen können Sie eine WebView und verwenden @Override shouldOverrideUrlLoading, wie im Beispiel von @huy.nguyen gezeigt, oder sogar verwenden http://localhost als Redirect_uri und lauschen Sie den laufenden Verbindungen.

    – Bhullnatik

    5. März 14 um 16:16 Uhr

OAuth 2.0 ist viel einfacher als 1.0 und kann ohne Hilfe einer externen Bibliothek durchgeführt werden. Wenn Sie jedoch bereits Scribe-Java verwenden, wird es noch einfacher.

Die Implementierung ist unkompliziert. Sie müssen eine erstellen WebView das hat einen Brauch WebViewClient die das Ladeverhalten für Ihre Rückruf-URL erfasst und überschreibt. Wenn also die WebView versucht, diese URL zu laden, können Sie den Prozess abfangen und einen Prüfer extrahieren. Der Prüfer kann an Scribe-Java übergeben werden, um ihn gegen ein Zugriffstoken auszutauschen.

Um den gesamten Prozess zu starten, müssen Sie nur Ihre sagen WebView um die Autorisierungs-URL zu laden.

Ich habe Beispielcode gehostet Hier. Die App authentifiziert sich mit der API von Buffer, aber der größte Teil des Codes kann wiederverwendet werden. Vielleicht interessieren Sie sich für die Fragment die meinen Brauch hostet WebView und der Hintergrund Arbeit das Zugriffstoken erhält.

Fühlen Sie sich frei, mir weitere Fragen zu stellen.

  • Hey, ich habe deinen Code überprüft, kann aber den Oauth-Mechanismus nicht verstehen. Können Sie die Extraktion des Prüfers im Code besser erklären?

    – amalBit

    5. März 14 um 11:28 Uhr

  • Du meinst das Linie? Der Rückruf würde wie folgt aussehen: callback_url?code="verifier" (dh: nguyenhuy.me/callback?code=”verifier”). Um den Prüfer zu extrahieren, müssen Sie nur den Wert von “Code” durch Aufrufen abrufen Uri.getQueryParameter(String).

    – huy.nguyen

    5. März 14 um 11:37 Uhr


  • Sie meinen ein funktionierendes Beispiel für LinkedIn OAuth? Ich kann es tun, aber der Code würde meinem erwähnten Code wirklich sehr ähnlich sehen.

    – huy.nguyen

    6. März 14 um 12:34 Uhr

OAuth 20 Autorisierung fur LinkedIn in Android
vntstudy

            @Override

        public boolean shouldOverrideUrlLoading(WebView view, String authorizationUrl) {
            //This method will be called when the Auth proccess redirect to our RedirectUri.
            //We will check the url looking for our RedirectUri.
            if(authorizationUrl.startsWith(REDIRECT_URI)){
                Log.i("Authorize", "");
                Uri uri = Uri.parse(authorizationUrl);
                //We take from the url the authorizationToken and the state token. We have to check that the state token returned by the Service is the same we sent.
                //If not, that means the request may be a result of CSRF and must be rejected.
                String stateToken = uri.getQueryParameter(STATE_PARAM);
                if(stateToken==null || !stateToken.equals(STATE)){
                    Log.e("Authorize", "State token doesn't match");
                    return true;
                }

                //If the user doesn't allow authorization to our application, the authorizationToken Will be null.
                String authorizationToken = uri.getQueryParameter(RESPONSE_TYPE_VALUE);
                if(authorizationToken==null){
                    Log.i("Authorize", "The user doesn't allow authorization.");
                    return true;
                }
                Log.i("Authorize", "Auth token received: "+authorizationToken);

                //Generate URL for requesting Access Token
                String accessTokenUrl = getAccessTokenUrl(authorizationToken);
                //We make the request in a AsyncTask
                new PostRequestAsyncTask().execute(accessTokenUrl);

            }else{
                //Default behaviour
                Log.i("Authorize","Redirecting to: "+authorizationUrl);
                webView.loadUrl(authorizationUrl);
            }
            return true;
        }

Und in Ihrer AsyncTask:

private class PostRequestAsyncTask extends AsyncTask<String, Void, Boolean>{

    @Override
    protected void onPreExecute(){
        pd = ProgressDialog.show(MainActivity.this, "", MainActivity.this.getString(R.string.loading),true);
    }

    @Override
    protected Boolean doInBackground(String... urls) {
        if(urls.length>0){
            String url = urls[0];
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpost = new HttpPost(url);
            try{
                HttpResponse response = httpClient.execute(httpost);
                if(response!=null){
                    //If status is OK 200
                    if(response.getStatusLine().getStatusCode()==200){
                        String result = EntityUtils.toString(response.getEntity());
                        //Convert the string result to a JSON Object
                        JSONObject resultJson = new JSONObject(result);
                        //Extract data from JSON Response
                        int expiresIn = resultJson.has("expires_in") ? resultJson.getInt("expires_in") : 0;

                        String accessToken = resultJson.has("access_token") ? resultJson.getString("access_token") : null;
                        Log.e("Tokenm", ""+accessToken);
                        if(expiresIn>0 && accessToken!=null){
                            Log.i("Authorize", "This is the access Token: "+accessToken+". It will expires in "+expiresIn+" secs");

                            //Calculate date of expiration
                            Calendar calendar = Calendar.getInstance();
                            calendar.add(Calendar.SECOND, expiresIn);
                            long expireDate = calendar.getTimeInMillis();

                            ////Store both expires in and access token in shared preferences
                            SharedPreferences preferences = MainActivity.this.getSharedPreferences("user_info", 0);
                            SharedPreferences.Editor editor = preferences.edit();
                            editor.putLong("expires", expireDate);
                            editor.putString("accessToken", accessToken);
                            editor.commit();

                            return true;
                        }
                    }
                }
            }catch(IOException e){
                Log.e("Authorize","Error Http response "+e.getLocalizedMessage());  
            }
            catch (ParseException e) {
                Log.e("Authorize","Error Parsing Http response "+e.getLocalizedMessage());
            } catch (JSONException e) {
                Log.e("Authorize","Error Parsing Http response "+e.getLocalizedMessage());
            }
        }
        return false;
    }

    @Override
    protected void onPostExecute(Boolean status){
        if(pd!=null && pd.isShowing()){
            pd.dismiss();
        }
        if(status){
            //If everything went Ok, change to another activity.
            Intent startProfileActivity = new Intent(MainActivity.this, ProfileActivity.class);
            MainActivity.this.startActivity(startProfileActivity);
        }
    }

};

.

581520cookie-checkOAuth 2.0-Autorisierung für LinkedIn in Android

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy