使用Angular.js - 如何从需要身份验证的后端提供二进制数据?

时间:2014-02-07 16:28:26

标签: javascript angularjs http rest http-headers

在我的angularjs应用程序中,我正在与后端服务器进行通信,后端服务器需要通过http头进行基本访问身份验证。我已按照here所述在客户端实现了身份验证机制。

angular.module('myAuthModule')
.config(['$httpProvider', '$stateProvider',
    function ($httpProvider, $stateProvider) {
        $httpProvider.interceptors.push('securityInterceptor');
    }])
.factory('securityInterceptor', ['$location', '$window', '$q',
    function ($location, $window, $q) {
        return {
            request: function (config) {
                config.headers = config.headers || {};
                if ($window.sessionStorage.token) {
                    config.headers['Auth-Key'] = $window.sessionStorage.token;
                }
                return config;
            },
            response: function (response) {
                if (response.status === 401 || response.status === 403) {
                    $location.path('/login');
                }
                return response || $q.when(response);
            }
        };
    }
]);

到目前为止一切顺利,在角度应用程序中处理xhr请求按预期工作。

问题是我需要提供pdf文档的下载链接。我的后端服务器有一个/Document/Pdf/:id资源,用于application/pdf响应,ContentDisposition: attachment也需要身份验证。我知道我无法使用xhr启动下载,但是两者都通过ngHref提供了文档下载链接,并调用了例如$window.open('/Document/Pdf/13')的函数,导致401 Unauthorized响应服务器

我在这里缺少什么?

2 个答案:

答案 0 :(得分:6)

探讨了 @Geoff Genz 给出的可能性,添加了第四个 - data-uri选项,遗憾的是不允许定义文件名 - 我决定采用不同的方法。

我在API中添加了一个方法,该方法根据正常验证的请求生成一次性下载链接并立即下载。角度处理程序变得非常简单

.factory('fileFactory', ['$http', '$window',
    function ($http, $window) {
        return {
            downloadFile: function (fileId) {
                return $http(
                    {
                        method: "POST",
                        data: fileId,
                        url: '/api/Files/RequestDownloadLink',
                        cache: false
                    }).success(function (response) {
                        var url = '/api/File/' + response.downloadId;
                        $window.location = url;
                    });
            }
        };
    }]);

这不完美,但我觉得最不好看。这也适用于我,因为我可以完全控制前端和后端。

答案 1 :(得分:1)

没有一个简单的解决方案。您已经发现无法通过Ajax下载,因此无法以这种方式设置自定义标头。您也不能在浏览器生成的GET(如href)或POST(如表单提交)上设置自定义标头。我可以建议三种不同的方法,所有这些方法都需要对您的服务器进行一些修改:

(1)在您的网页上使用基本或摘要身份验证,因此浏览器将生成并发送带有这些凭据的授权标题。

(2)将令牌设置在“授权”cookie中,该cookie将随请求一起传递并验证令牌服务器端。

(3)最后,我们实现这一点的方法是使用POST请求而不是GET进行下载。我们在同一页面上POST到一个隐藏的IFrame,并让服务器在响应上设置适当的Content-Disposition标题,例如“attachment; filename =”blah.pdf“”。然后,我们将授权令牌作为表单中的隐藏字段发送。

这些都不是理想的,我知道我们的解决方案有点像hacky,但我没有看到任何更优雅的方法。