0

I've created a small web application in AngularJS that is using basic authorization. For this purpose I have added following line in to app.js:

app.js

.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.headers.common['Content-Type'] = 'application/json';
    $httpProvider.defaults.headers.common['Accept'] = 'application/json';
    $httpProvider.defaults.headers.common['Authorization'] = "Basic am9obkBqb2huLmNvbTpibGE=";
}]);

On server side I'm using Spring MVC to display the file:

ImageResourceController.java

@Controller
@RequestMapping("/common/image")
public class ImageResourceController {
    @Autowired
    private FileService fileService;

    /***************************************************
    * URL: /api/common/image/{id}
    * Method: GET
    * get(): gets an image according to it's uuid from the db
    * @param id : String id (UUID)
    * @return ByteArray containing image
    ****************************************************/
    @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
    @ResponseBody
    public byte[] get(@PathVariable("id") String id) throws IOException {
        FileMeta fileMeta = fileService.loadFile(id);

        return IOUtils.toByteArray(fileMeta.getInputStream());
    }
}

FileService.java

/**
 * File Service Layer takes care about the file operations to the database.
 * <p>
 */
@Service
public class FileService {
    @Autowired
    GridFsOperations gridOperation;

    /***************************************************
     * Loads a file with metadata from GridFS.
     * <p>
     * @param uuid : String uuid
     * @return fileMeta : FileMeta fileMeta
     ****************************************************/
    public FileMeta loadFile(String uuid) {
        FileMeta fileMeta = new FileMeta();

        try {
            GridFSDBFile gridFile = gridOperation.findOne(new Query(Criteria.where("metadata.UUID").is(uuid)));
            fileMeta.setMetaData(gridFile.getMetaData().toMap());
            fileMeta.setInputStream(gridFile.getInputStream());
        } catch (Exception e) {
            fileMeta = null;
            e.printStackTrace();
        }

        return fileMeta;
    }
}

FileMeta.java

/**
* FileMeta is used to transfer a file with metadata.
*
*/
public class FileMeta {
    private Map<String, Object> metaData;
    private InputStream inputStream;

    public Map<String, Object> getMetaData() {
        return metaData;
    }

    public void setMetaData(Map<String, Object> metaData) {
       this.metaData = metaData;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }
}

spring-security.xml (intercept-url pattern="/api/** applies)

<!-- Define security patterns to allow/disallow access -->
<http pattern="/favicon.ico*" security="none" />
<http pattern="/resources/**" security="none" />
<http use-expressions="true" create-session="stateless" auto-config='true' entry-point-ref="restAuthenticationEntryPoint">
    <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
    <http-basic/>
</http>

Authorization is working for every call I do with $http and $resource. But when I want to load my image from the database with img ng-src (I'm using the MongoDB File Store), then the Authorization header isn't parsed to the server and login fails.

<img ng-src="/api/common/image/5ac8618c-7979-4940-a038-1ea91fbd55b3"/><br/>

Can somebody tell me how I can send the Authorization header also with img ng-src?

I'm using AngularJS 1.2.0.

Thanks for your help.

Christopher Armstrong
  • 3,477
  • 6
  • 34
  • 40
  • 2
    Sorry, but more information is required. You're getting the image from a database which can only be accessed through authorization? I'm not quite getting the connection between ng-src and your authorization process. Why not saving the image to a variable, when the authorization is successful and base64-encode it? You need to save it somewhere, you couldn't add header information to a normal src either, how should this work? – hugo der hungrige Nov 12 '13 at 23:47
  • Thanks for your message. Yes, the image can only be fetched from the db when authorized. Authorization is normal Basic Auth on server side. I'm sorry but the backend is written in Spring and I didn't want to mix the code. I noticed that the headers are not parsed to Spring by AngularJS. I thought it might confuse people if there is more Spring code then AngularJS code. I assumed that AngularJS is also sending header information for img ng-src. But if this is not the case then you're right. Then I'll have to fetch the image in to a variable first. – Christopher Armstrong Nov 13 '13 at 19:14
  • 1
    ng-src just works like src with the difference that you're able to use it in conjunction with $scope-variables. I'm not 100% sure, but I think base64-encoding is the only way to handle this issue client-side. Thanks for not mixing though, you would have had me quite confused (: – hugo der hungrige Nov 13 '13 at 23:25
  • Thanks your answer is appreciated. I'm just playing with binary and base64 encoding. Guess I still need a while to figure out how that works again :) – Christopher Armstrong Nov 13 '13 at 23:34
  • Its no fun, I can assure you ;) I would post some code, but its proprietary unfortunately :( – hugo der hungrige Nov 13 '13 at 23:35
  • Yea, I'm trying to get it to work since 2 hours already. No problem. I'll also get this working. – Christopher Armstrong Nov 13 '13 at 23:41

1 Answers1

1

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="/api/common/image/5ac8618c-7979-4940-a038-1ea91fbd55b3"/>

But you can also make it dynamic with <img http-src="/api/common/image/{{imageId}}"/> for example.

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

Community
  • 1
  • 1
Anthony O.
  • 22,041
  • 18
  • 107
  • 163