Как добавить токен аутентификации в заголовок в библиотеке Picasso

Я использую библиотеку picasso для загрузки растрового изображения, поэтому в API мне нужно передать токен в заголовках. Я попробовал ниже код из этой темы Android Picasso library, Как добавить заголовки аутентификации ?

public static Picasso getImageLoader(final Context context) {
    // fetch the auth value
    sSharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());

    Picasso.Builder builder = new Picasso.Builder(context);
    builder.downloader(new OkHttpDownloader(context) {
        @Override
        protected HttpURLConnection openConnection(Uri uri) throws IOException {
            HttpURLConnection connection = super.openConnection(uri);
            connection.setRequestProperty(Constant.HEADER_X_API_KEY, sSharedPreferences.getString(SharedPreferenceKeys.JSESSIONID, ""));
            return connection;
        }
    });
    sPicasso = builder.build();
    return sPicasso;
}

Запрос Пикассо

mTarget = new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
        mdpImageView.setImageBitmap(bitmap);
        Logger.d(TAG, "Test");
    }

    @Override
    public void onBitmapFailed(Drawable drawable) {
        Logger.d(TAG, "Test");
    }

    @Override
    public void onPrepareLoad(Drawable drawable) {
        Logger.d(TAG, "Test");
    }
};

CustomPicasso.getImageLoader(getActivity()).with(getActivity()).load(URL).into(mTarget);

Вопрос

Я отладил свой код и вижу, что он никогда не вызывал openconnection метод переопределения OkHttpDownloader, поэтому мой запрос всегда терпит неудачу, и в конце он вызывает onBitmapFailed.

Пожалуйста, помогите, что мне нужно сделать, чтобы правильно передать значение заголовков.

Заранее спасибо.


person N Sharma    schedule 30.09.2014    source источник


Ответы (6)


На решение этой проблемы ушло два дня. Для пользовательского загрузчика вам не нужно вызывать метод with, поскольку он инициализирует загрузчик по умолчанию и экземпляр picasso. Просто сделайте следующее, как показано ниже, это поможет вам получить растровое изображение.

Picasso.Builder builder = new Picasso.Builder(getActivity());
picasso =  builder.downloader(new OkHttpDownloader(getActivity()) {
    @Override
    protected HttpURLConnection openConnection(Uri uri) throws IOException {
        HttpURLConnection connection = super.openConnection(uri);
        connection.setRequestProperty(Constant.HEADER_X_API_KEY, mSharedPreferences.getString(SharedPreferenceKeys.JSESSIONID, ""));
        return connection;
    }
}).build();
picasso.load(url).into(mTarget);
person N Sharma    schedule 02.10.2014

У меня была та же проблема, но в моем случае я забыл, что у меня есть самозаверяющий сертификат на моем сервере, поэтому OkHttp получал сертификат, а затем отказывался получать какие-либо изображения. Следовательно, со стороны сервера выглядело так, будто Пикассо не делал никаких запросов.

Итак, исправление заключалось в создании небезопасного клиента OkHttp, который не проверяет сертификаты:

static OkHttpClient getUnsafeOkHttpClient() {
  try {
      // Create a trust manager that does not validate certificate chains
      final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
          @Override
          public void checkClientTrusted(java.security.cert.X509Certificate[] chain,
                  String authType) throws CertificateException {
          }

          @Override
          public void checkServerTrusted(java.security.cert.X509Certificate[] chain,
                  String authType) throws CertificateException {
          }

          @Override
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
              return null;
          }
      } };

      // Install the all-trusting trust manager
      final SSLContext sslContext = SSLContext.getInstance("SSL");
      sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
      // Create an ssl socket factory with our all-trusting manager
      final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

      OkHttpClient okHttpClient = new OkHttpClient();
      okHttpClient.setSslSocketFactory(sslSocketFactory);
      okHttpClient.setHostnameVerifier(new HostnameVerifier() {
          @Override
          public boolean verify(String hostname, SSLSession session) {
              return true;
          }
      });

      return okHttpClient;
  } catch (Exception e) {
      throw new RuntimeException(e);
  }
}

Затем используйте его в моем CustomOkHttpDownloader:

static class CustomOkHttpDownloader extends OkHttpDownloader {

    private String accessToken;

    public CustomOkHttpDownloader(Context context, String accessToken) {
        super(getUnsafeOkHttpClient());
        this.accessToken = accessToken;
    }

    @Override
    protected HttpURLConnection openConnection(final Uri uri) throws IOException {
        HttpURLConnection connection = super.openConnection(uri);
        connection.setRequestProperty("Authorization", "Bearer " + accessToken);
        Log.d(LOG_TAG, "Creating connection for " + uri + " with " + accessToken);
        return connection;
    }
}
person Mark Butler    schedule 18.10.2014

Picasso picasso;
Builder builder = new Picasso.Builder(this);
picasso = builder.loader(new BasicAuthOkHttpLoader(this)).build();

внедрить класс Loader в BasicAuthOkHttpLoader.

В методе переопределения Load напишите свою логику аутентификации.

 @Override
  public Response load(String url, boolean localCacheOnly) throws IOException {
    HttpURLConnection connection = client.open(new URL(url));
    String authString = "username:password";
    String authStringEnc = Base64.encodeToString(authString.getBytes(), Base64.NO_WRAP);
    connection.setRequestProperty("Authorization", "Basic " + authStringEnc);
    connection.setUseCaches(true);

    // no caching happens without this setting in our scenario
    connection.setRequestProperty("Cache-Control", "max-stale=2592000");// 30 days
    if (localCacheOnly) {
      connection.setRequestProperty("Cache-Control", "only-if-cached");
    }

    boolean fromCache = parseResponseSourceHeader(connection.getHeaderField(RESPONSE_SOURCE));

    return new Response(connection.getInputStream(), fromCache);
  }

Подробнее: https://gist.github.com/dkunzler/5636491

person Harsha Vardhan    schedule 30.09.2014
comment
Некоторые классы в этом коде устарели. Пожалуйста, укажите версию библиотеки picasso и okhttp, которую я должен использовать для этого. - person N Sharma; 01.10.2014
comment
picasso-1.1.1.jar доступен - person Harsha Vardhan; 01.10.2014

Я использовал другую библиотеку AQuery и смог получить не только авторизованный доступ к прокрутке picassa за несколько минут, но и библиотека использовала учетные данные телефонов, поэтому это было очень просто.

Даже если вы не используете эту библиотеку, взгляните на то, как я получил экспериментальный метод включения только необходимых полей, работающих ниже. Меньшие результаты обеспечивают более быстрый сетевой ввод-вывод и огромную разницу в процессорном времени. Поскольку JSON меньше, он анализируется быстрее, а DOM для xml меньше, поэтому создается очень быстро.

Здесь я использую экспериментальный метод возврата только тех полей, которые я хочу для общедоступных альбомов для пользователя в формате XML.

GoogleHandle handle = new GoogleHandle(this.getActivity(),
            AQuery.AUTH_PICASA, AQuery.ACTIVE_ACCOUNT);

    // experimental fields method encoding the data part of the query string only.
    String url = "";
    try {
        url = "https://picasaweb.google.com/data/feed/api/user/default?kind=album&access=public&fields="
                + URLEncoder
                        .encode("entry(title,id,gphoto:numphotosremaining,gphoto:numphotos,media:group/media:thumbnail)",
                                "UTF-8");
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        //whatever I know this will work
        // I hard coded the string.
    }


        aq.auth(handle).progress(R.id.pbTrackerAlbumsProgress)
                .ajax(url, XmlDom.class, this, "renderAlbums");



public void renderAlbums(String url, XmlDom xml, AjaxStatus status) {
    List<PicasaAlbum> entries = convertAll(xml);


    if (entries.size() > 0) {
        isAuthError = false;
        // if the xml iis null we can't display the list
        // we can setup the adapter
        aa = new ArrayAdapter<PicasaAlbum>(this.getActivity(),
                R.layout.listview_item_album, entries) {

            public View getView(int position, View convertView,
                    ViewGroup parent) {

                if (convertView == null) {

                    // convertView =
                    // View.inflate(getActivity().getBaseContext(),
                    // R.layout.listview_item_album, parent);
                    convertView = getActivity().getLayoutInflater()
                            .inflate(R.layout.listview_item_album, parent,
                                    false);
                }

                PicasaAlbum picasaAlbum = getItem(position);

                AQuery aqLocal = aq.recycle(convertView);

                aqLocal.id(R.id.albumTitle).text(picasaAlbum.title);
                // aq.id(R.id.meta).text(picasaAlbum.author);

                String tbUrl = picasaAlbum.thumbNailUrl.toString();

                Bitmap placeholder = aqLocal
                        .getCachedImage(R.drawable.ic_launcher2);

                if (aqLocal.shouldDelay(position, convertView, parent,
                        tbUrl)) {

                    aqLocal.id(R.id.tb).image(placeholder);
                } else {
                    aqLocal.id(R.id.tb).image(tbUrl, true, true, 0,
                            R.drawable.ic_launcher2x, placeholder,
                            AQuery.FADE_IN_NETWORK, 0);
                }

                return convertView;

            }

        };
        ((TextView) view.findViewById(R.id.tvTrackerExistingAlbum))
                .setText("Select the album for route marker photos");
        ((ProgressBar) view.findViewById(R.id.pbTrackerAlbumsProgress))
                .setVisibility(View.GONE);
        ListView lv = (ListView) view.findViewById(R.id.lvTrackerAlbums);

        lv.setAdapter(aa);
        aa.notifyDataSetChanged();
        lv.setVisibility(View.VISIBLE);
    }
}
person danny117    schedule 30.09.2014

Picasso 2.5, okHttpDownloader изменился. Пожалуйста, перейдите по ссылке ниже, чтобы добавить заголовки аутентификации

https://github.com/square/picasso/issues/900

person rahulrv    schedule 08.05.2015

Это, наконец, сработало для меня, просто вызовите его, а затем используйте экземпляр picasso, здесь я добавляю токен доступа. Но вы также можете добавить имя пользователя и пароль.

private void setupPicasso()
{        
    //need to set picasso up to use auth - took a while to work this out!
    final Context c = context;
    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    String token = <token you got when you logged in>;
                    String authString = "Bearer "+token;                        
                    Request newRequest = chain.request().newBuilder()
                            .addHeader("Authorization", authString)
                            .build();
                    return chain.proceed(newRequest);
                }
            })
            .build();
    picasso = new Picasso.Builder(context)
            .downloader(new OkHttp3Downloader(client))
            .build();
}
person 68060    schedule 11.10.2017