angular http: how to call images with custom headers?
Asked Answered
C

5

22

In the html view, images are displayed like this:

<img ng-src="{{element.image.url}}"> 

element.image.url points to an url like: /rest_api/img/12345678.

This is working fine, images are displayed.

Now, I add authentication:

Before the user is authenticated, every resources respond with an http error 401, images too. When authentication succeeds, a token is placed in a custom headers and sent with every $http requests, allowing access the resources:

$http.defaults.headers.common['Authorization'] = token; 

This is working fine for Json files loaded with $resource. But the direct links to the images are still 401 after authentication.

How to call the images with custom headers?

Or any advice on how I should do this.

Cypro answered 6/2, 2014 at 20:37 Comment(7)
How are you handling authentication server side? Is it cookie / sessionId? Basic authentication? As far as I know, you can't append custom headers for non-XHR requests (script, CSS, images, videos, etc.). Those are handled by the browser and you might be able to control your user-agent header programmatically before / after each request but the only data that passes with those requests include that basic data and cookies.Antoinetteanton
Server side is handled by Ez publsih rest Api. There are two cookies: PHPSESSID and eZSESSID and a token (OAUTH) handled by angular. Do you mean that if the session cookie is defined, then the image call should work?Tomsk
I don't know how Ez Publish works, but yes, the idea is that the back-end would handle the authentication and return the image after verifying the sessionId. Are your images on the same host as whatever you're authenticating with?Antoinetteanton
yes, images are on the same host.Tomsk
is there a reason you would want to secure a static resource in the first place? perhaps just serve the images from the backend as is (no authentication required).Josh
@EliranMalka The reason is that this images are content and should only be seen by authenticated users (no direct access allowed).Tomsk
in that case, don't rely on the browser to fetch it - use javascript to get the image url, and authenticate in the backend (and in the frontend).Josh
A
12

As said here you can use angular-img-http-src (bower install --save angular-img-http-src if you use Bower).

If you look at the code, it uses URL.createObjectURL and URL.revokeObjectURL which are still draft on 19 April 2016. So look if your browser supports it.

In order to use it, declare 'angular.img' as a dependency to your app module (angular.module('myapp', [..., 'angular.img'])), and then in your HTML you can use http-src attribute for <img> tag.

In your example it would be: <img http-src="{{element.image.url}}">

Of course, this implies that you have declared an interceptor using $httpProvider.interceptors.push to add your custom header or that you've set statically your header for every requests using $http.defaults.headers.common.MyHeader = 'some value';

Actinia answered 6/2, 2014 at 20:37 Comment(2)
thank you for this helpful answer! Browser-compatibility link, example, and the reminder about declaration. 5 stars!Cowpea
Yeah, we need a way to up vote +10, super simple issue especially if your resources are served from a service hosted on another domain.Nephritis
S
9

There is a vary simple answer for that. You should use: angular-img-http-src.

Problem:

You used token based auth and you need to serve images from secured routes.

Solution:

Use http-src instead of ng-src and it will fetch images using the $http service - meaning Authorization headers added via interceptors will be present - then build a Blob and set the src to an objectURL.

It works perfectly on my project.

Steve answered 6/2, 2014 at 20:37 Comment(0)
W
1

I am facing the same problem. The best solution I found is passing the Authorization token as a query parameter.

For example :

<img src="http://myhost.com/image/path?accessToken=123456789" >

This way you can secure those images only for your REST consumers.

Worlock answered 6/2, 2014 at 20:37 Comment(1)
Very pragmatic approachOctane
B
1

Consider the URL be http://foo.com/bar.png

In your controller,

angular.module('foo')
  .controller('fooCtrl', ['$sce',
    function($sce) {
      $scope.dataSrc = "http://foo.com/bar.png"
      $scope.src = $sce.trustAsResourceUrl($scope.dataSrc)
    }
  ])

And in your view,

<img ng-src="{{src}}" />

.. seems to do the trick.

Beastly answered 6/2, 2014 at 20:37 Comment(1)
@jayM If it solved your problem, please mark the answer as correct.Beastly
A
-1

As far as I know it's not possible to pass additional headers with asset requests (scripts, images, media, CSS files that the browser loads while rendering the page). That's all controlled by the browser. Only when making a XHR (AJAX) request can you modify headers.

I would suggest looking at your server side authentication and seeing if there's a solution there.

Antoinetteanton answered 7/2, 2014 at 21:20 Comment(2)
from mozilla's MDN: You can add your own HTTP headers to any request the application makes […] an <img> element in content…Tomsk
@desgnl - that solution requires elevated privileges to access XPCOM interfaces - which a web page won't have.Knowlton

© 2022 - 2024 — McMap. All rights reserved.