私はAngularで認証を処理します。認証はJWTトークンによって処理されます。つまり、すべての要求には必要なすべての情報を含む「認証」ヘッダーがあります。
これはREST呼び出しに対してうまく機能しますが、バックエンドでホストされているファイルのダウンロードリンクを処理する方法がわかりません(ファイルはWebサービスがホストされている同じサーバーにあります)。
通常の_<a href='...'/>
_リンクを使用することはできません。これらのリンクはヘッダーを保持せず、認証が失敗するためです。 window.open(...)
のさまざまな呪文についても同じです。
私が考えたいくつかのソリューション:
上記のすべては満足できるものではありません。
1は現在使用しているソリューションです。私は2つの理由でそれが好きではありません:1つ目はセキュリティに関して理想的ではありません、2つ目は動作しますが、特にサーバー上で非常に多くの作業が必要です:何かをダウンロードするには、新しい「ランダムな"url、それをどこかに(おそらくDB上に)しばらく保存し、クライアントに返します。クライアントはURLを取得し、window.openまたはそれに類似したものを使用します。要求された場合、新しいURLはそれがまだ有効かどうかを確認し、データを返します。
2は少なくとも同じくらいの作業のようです。
3は、利用可能なライブラリを使用する場合でも、多くの作業が必要であり、多くの潜在的な問題があります。 (独自のダウンロードステータスバーを提供し、ファイル全体をメモリに読み込み、ユーザーにファイルをローカルに保存するように要求する必要があります)。
タスクは非常に基本的なもののようですが、使用できるもっと簡単なものはないかと思っています。
「Angular way」という解決策を必ずしも探しているわけではありません。通常のJavascriptで十分でしょう。
ダウンロード属性 、 フェッチAPI 、および RL.createObjectURL を使用して、クライアントにダウンロードする方法を次に示します。 JWTを使用してファイルを取得し、ペイロードをblobに変換し、blobをobjectURLに入れ、アンカータグのソースをそのobjectURLに設定し、javascriptでそのobjectURLをクリックします。
let anchor = document.createElement("a");
document.body.appendChild(anchor);
let file = 'https://www.example.com/some-file.pdf';
let headers = new Headers();
headers.append('Authorization', 'Bearer MY-TOKEN');
fetch(file, { headers })
.then(response => response.blob())
.then(blobby => {
let objectUrl = window.URL.createObjectURL(blobby);
anchor.href = objectUrl;
anchor.download = 'some-file.pdf';
anchor.click();
window.URL.revokeObjectURL(objectUrl);
});
download
属性の値は、最終的なファイル名になります。必要に応じて、コンテンツ処理応答ヘッダーから目的のファイル名をマイニングできます 他の回答で説明されているように 。
JWTエバンジェリストとして知られるAuth0のMatias Woloskiの このアドバイス に基づいて、 Hawk で署名付きリクエストを生成することで解決しました。
ウォロスキーの引用:
これを解決する方法は、たとえばAWSのように署名付きリクエストを生成することです。
ここに例を示します アクティベーションリンクに使用されるこの手法の。
ダウンロードURLに署名するAPIを作成しました。
要求:
POST /api/sign
Content-Type: application/json
Authorization: Bearer...
{"url": "https://path.to/protected.file"}
応答:
{"url": "https://path.to/protected.file?bewit=NTUzMDYzZTQ2NDYxNzQwMGFlMDMwMDAwXDE0NTU2MzU5OThcZDBIeEplRHJLVVFRWTY0OWFFZUVEaGpMOWJlVTk2czA0cmN6UU4zZndTOD1c"}
署名付きURLを使用すると、ファイルを取得できます
要求:
GET https://path.to/protected.file?bewit=NTUzMDYzZTQ2NDYxNzQwMGFlMDMwMDAwXDE0NTU2MzU5OThcZDBIeEplRHJLVVFRWTY0OWFFZUVEaGpMOWJlVTk2czA0cmN6UU4zZndTOD1c
応答:
Content-Type: multipart/mixed; charset="UTF-8"
Content-Disposition': attachment; filename=protected.file
{BLOB}
これにより、ユーザーが1回クリックするだけですべてを実行できます。
function clickedOnDownloadButton() {
postToSignWithAuthorizationHeader({
url: 'https://path.to/protected.file'
}).then(function(signed) {
window.location = signed.url;
});
}
ダウンロード用のトークンを生成します。
内でangular一時的なトークンを取得するための認証されたリクエスト(1時間など)を行い、それをgetパラメーターとしてURLに追加します。この方法で、好きな方法でファイルをダウンロードできます開いた ...)
追加のソリューション:基本認証を使用します。バックエンドで少し作業が必要ですが、トークンはログに表示されず、URL署名を実装する必要はありません。
URLの例は次のとおりです。
_http://jwt:<user jwt token>@some.url/file/35/download
_
ダミートークンの例:
_http://jwt:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIwIiwibmFtZSI6IiIsImlhdCI6MH0.KsKmQOZM-jcy4l_7NFsv1lWfpH8ofniVCv75ZRQrWno@some.url/file/35/download
_
その後、これを_<a href="...">
_またはwindow.open("...")
で突き止めることができます。残りはブラウザが処理します。
ここでの実装はユーザー次第であり、サーバーのセットアップに依存します-_?token=
_クエリパラメーターを使用することとそれほど違いはありません。
Laravelを使用して、簡単な方法で基本認証パスワードをJWT _Authorization: Bearer <...>
_ヘッダーに変換し、通常の認証ミドルウェアが残りを処理できるようにしました。
_class CarryBasic
{
/**
* @param Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, \Closure $next)
{
// if no basic auth is passed,
// or the user is not "jwt",
// send a 401 and trigger the basic auth dialog
if ($request->getUser() !== 'jwt') {
return $this->failedBasicResponse();
}
// if there _is_ basic auth passed,
// and the user is JWT,
// shove the password into the "Authorization: Bearer <...>"
// header and let the other middleware
// handle it.
$request->headers->set(
'Authorization',
'Bearer ' . $request->getPassword()
);
return $next($request);
}
/**
* Get the response for basic authentication.
*
* @return void
* @throws \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
*/
protected function failedBasicResponse()
{
throw new UnauthorizedHttpException('Basic', 'Invalid credentials.');
}
}
_