OkHTTP 中的身份验证和身份验证Header

Authentication and Authentication Header in OkHTTP

我面临一个相当简单的情况,但我无法全神贯注。也许 OkHttp 专家可以照亮我的道路。

我在 android 应用上将 Picasso, Retrofit and OkHttp 用于多种用途。好极了!。正如我正确阅读的那样,开发人员应该努力保持 OkHttpClient(如此处阅读)。

考虑到这种方法,我希望我的任何 HTTP 调用(无论是 API 调用、图像加载还是资源下载)都可以:

  1. 发送请求
  2. 如果收到 HTTP401,则发送另一个发送回令牌的 HTTP 请求
  3. 收到该令牌后,调用 re-emitted,该令牌包含在 headers
  4. 任何后续调用(无论是 API、资源还是图像调用)都应使用该令牌,直到收到下一个 HTTP401(无效令牌)。

当然,我会为 Retrofit 和 Picasso 重用 相同的 客户端。

我正在考虑的一种方法是混合使用 Authenticator and an application Interceptor。身份验证器应该捕获 HTTP401,但我可以让它同时发出另一个同步请求、存储令牌并激活新的拦截器吗?

看来我自己找到了解决该问题的方法,所以让我们与大家分享知识。

为此,OkHttp 已经提供了所有必要的钩子。

  1. 确保使用身份验证器
  2. 验证器成功后安装拦截器
  3. Return 带有良好令牌的请求。

这也意味着 Authenticator 处理 HTTP 以设置您的令牌(在另一个 android 服务中完成)。

okHttpClient.setAuthenticator(new Authenticator() {
            @Override
            public Request authenticate(Proxy proxy, Response response) {

                AccountManager accountManager = AccountManager.get(context);
                Account[] accounts = accountManager.getAccountsByType(Authenticator.ACCOUNT_TYPE);
                // No account, do not even try to authenticate
                if (accounts.length == 0) {
                    Log.i(TAG, "... But we dont have any account yet, so I will just back off for now.");
                    return null;
                }

                Account account = accounts[0];

                try {
                    final String mCurrentToken = accountManager.blockingGetAuthToken(account, "", false);

                    // For now, we just re-install blindly an interceptor
                    okHttpClient.interceptors().clear();
                    Log.i(TAG, "... Installing interceptor after authentication");
                    okHttpClient.interceptors().add(new Interceptor() {
                            @Override public Response intercept(Chain chain) throws IOException {
                                Request request = chain.request();
                                Request newReq = request.newBuilder()
                                    .addHeader("Authorization", mCurrentToken)
                                    .build();
                                Response response = chain.proceed(newReq);

                                return response;
                            }
                        });
                    Log.i(TAG, "Install temporary auth token in request");
                    return response.request().newBuilder()
                        .addHeader("Authorization", mCurrentToken)
                        .build();

                } catch (OperationCanceledException e) {
                    Log.e(TAG, "Interrupted exception");
                    return null;
                } catch (AuthenticatorException e) {
                    Log.e(TAG, "Authentication error");
                    return null;
                } catch (IOException e) {
                    Log.e(TAG, "IO Error");
                    return null;                        
                }
            }


            @Override
            public Request authenticateProxy(Proxy proxy, Response response) {
                return null; // Null indicates no attempt to authenticate.
            }
        })

有了这个,在Picasso和Retrofit中使用这个OkClient就可以了。