如何在Android上实现OAuth2授权

Aug*_*ani 3 android oauth-2.0

我需要在我的应用中添加 OAuth2 授权。我只有客户端 ID、客户端机密和用户名(电子邮件)。我需要得到令牌。你能给我一些关于如何做到这一点的建议吗?库或示例代码?

Mat*_* Ke 9

您可以使用AppAuth进行 OAuth2 授权。

有关示例,请参阅https://github.com/openid/AppAuth-Android


以下是 AppAuth 文档的缩短版本。

概述

建议原生应用使用授权码流。

这个流程实际上由四个阶段组成:

  1. 指定授权服务配置。
  2. 通过浏览器授权,以获得授权码。
  3. 交换授权码,以获取访问和刷新令牌。
  4. 使用访问令牌访问受保护的资源服务。

1.创建授权服务配置

首先,创建授权服务的配置,将在第二和第三阶段使用。

AuthorizationServiceConfiguration mServiceConfiguration =
    new AuthorizationServiceConfiguration(
        Uri.parse("https://example.com/authorize"), // Authorization endpoint
        Uri.parse("https://example.com/token")); // Token endpoint

ClientAuthentication mClientAuthentication =
    new ClientSecretBasic("my-client-secret"); // Client secret
Run Code Online (Sandbox Code Playgroud)

(不建议在本机应用程序中使用静态客户端机密。)

2.请求授权,获取授权码

要接收授权回调,请在清单文件中定义以下活动。(您不需要实施此活动。此活动将充当您授权请求的代理。)

<activity
        android:name="net.openid.appauth.RedirectUriReceiverActivity"
        tools:node="replace">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="com.example"/> <!-- Redirect URI scheme -->
    </intent-filter>
</activity>
Run Code Online (Sandbox Code Playgroud)

构建并执行授权请求。

private void authorize() {
    AuthorizationRequest authRequest = new AuthorizationRequest.Builder(
        mServiceConfiguration,
        "my-client-id", // Client ID
        ResponseTypeValues.CODE,
        Uri.parse("com.example://oauth-callback") // Redirect URI
    ).build();

    AuthorizationService service = new AuthorizationService(this);

    Intent intent = service.getAuthorizationRequestIntent(authRequest);
    startActivityForResult(intent, REQUEST_CODE_AUTH);
}
Run Code Online (Sandbox Code Playgroud)

处理授权响应。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (requestCode != REQUEST_CODE_AUTH) {
        return;
    }

    AuthorizationResponse authResponse = AuthorizationResponse.fromIntent(intent);
    AuthorizationException authException = AuthorizationException.fromIntent(intent);

    mAuthState = new AuthState(authResponse, authException);

    // Handle authorization response error here

    retrieveTokens(authResponse);
}
Run Code Online (Sandbox Code Playgroud)

3.交换授权码

private void retrieveTokens(AuthorizationResponse authResponse) {
    TokenRequest tokenRequest = response.createTokenExchangeRequest();

    AuthorizationService service = new AuthorizationService(this);

    service.performTokenRequest(request, mClientAuthentication,
            new AuthorizationService.TokenResponseCallback() {
        @Override
        public void onTokenRequestCompleted(TokenResponse tokenResponse,
                AuthorizationException tokenException) {
            mAuthState.update(tokenResponse, tokenException);

            // Handle token response error here

            persistAuthState(mAuthState);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

令牌检索成功完成后,坚持下去,AuthState以便您可以在下一个应用程序(重新)启动时重用它。

4. 访问受保护的资源服务

用于使用performActionWithFreshTokens新的访问令牌执行 API 调用。(它会自动确保令牌是新鲜的,并在需要时刷新它们。)

private void prepareApiCall() {
    AuthorizationService service = new AuthorizationService(this);

    mAuthState.performActionWithFreshTokens(service, mClientAuthentication,
            new AuthState.AuthStateAction() {
        @Override
        public void execute(String accessToken, String idToken,
                AuthorizationException authException) {
            // Handle token refresh error here

            executeApiCall(accessToken);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

执行 API 调用。(这AsyncTask只是为了简单起见。它可能不是执行 API 调用的最佳解决方案。)

private void executeApiCall(String accessToken) {
    new AsyncTask<String, Void, String>() {
        @Override
        protected String doInBackground(String... params) {
            OkHttpClient client = new OkHttpClient();
            Request request = new Request.Builder()
                    .url("https://example.com/api/...") // API URL
                    .addHeader("Authorization",
                            String.format("Bearer %s", params[0]))
                    .build();

            try {
                Response response = client.newCall(request).execute();
                return response.body().string();
            } catch (Exception e) {
                // Handle API error here
            }
        }

        @Override
        protected void onPostExecute(String response) {
            ...
        }
    }.execute(accessToken);
}
Run Code Online (Sandbox Code Playgroud)

  • AppAuth 是 Google 推荐的。它使用 Chrome 自定义选项卡来进行授权请求。Chrome 自定义选项卡比设备的默认网络浏览器具有一些优势。例如,自定义选项卡与最后显示的活动重叠。(请参阅以下来自 Google 的演讲:https://youtu.be/DdQTXrk6YTk?t=220) (2认同)