在我的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
响应服务器
我在这里缺少什么?
答案 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,但我没有看到任何更优雅的方法。