How to add authentication token in header in Picas

2019-02-07 10:39发布

I am using the picasso library to download the bitmap so in the api I need to pass the token in the headers. I tried below code from this thread Android Picasso library, How to add authentication headers?

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;
}

Picasso Request

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);

Question

I debugged my code & I see it never called openconnection override method of OkHttpDownloader so my request always fail & at the end it calls onBitmapFailed.

Please help what are things I have to do to pass headers value correctly.

Thanks in advance.

6条回答
Anthone
2楼-- · 2019-02-07 10:58

I used another library AQuery and was able to get not only authorized access to picassa rolling in a few minutes but also the library used the phones credentials so it was extremely easy.

Even if you don't use this library take a look at how I get the experimental method of including only the fields needed working below. The smaller results makes for faster network io and a huge difference in CPU. Because the JSON is smaller it parses faster and or the DOM for the xml is smaller it is built extremely fast.

Here I'm using the experimental method of returning only fields I want for public albums for the user in 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);
    }
}
查看更多
Juvenile、少年°
3楼-- · 2019-02-07 10:59

Picasso 2.5, The okHttpDownloader has changed. Please refer the below link to add the authentication headers

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

查看更多
Fickle 薄情
4楼-- · 2019-02-07 11:00

I had the same problem but in my case I had forgotten I had an self-signed certificate on my server so OkHttp was getting the certificate and then refusing to retrieve any images. Consequently from the server side it looked like Picasso was not making any requests.

So the fix was to create an unsafe OkHttp client that doesn't test certificates:

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);
  }
}

Then use it in my 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;
    }
}
查看更多
地球回转人心会变
5楼-- · 2019-02-07 11:08

It took two days to resolve this problem. For custom downloader you don't have to call with method because this will initialize the default downloader & picasso instance. Simply do below like this that will help you to get bitmap.

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);
查看更多
闹够了就滚
6楼-- · 2019-02-07 11:11
Picasso picasso;
Builder builder = new Picasso.Builder(this);
picasso = builder.loader(new BasicAuthOkHttpLoader(this)).build();

implement Loader to BasicAuthOkHttpLoader class.

In override Load method, write ur authentication logic.

 @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);
  }

For more details: http Basic auth the implementation of a custom loader

查看更多
Evening l夕情丶
7楼-- · 2019-02-07 11:11

This finally worked for me, just call it and then use the picasso instance, here I add an access token. But you could also add username and password.

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();
}
查看更多
登录 后发表回答