LoginSignup
3
2

More than 3 years have passed since last update.

Android/iOSから署名付きcookieでCloudFrontにアクセスする

Last updated at Posted at 2018-10-23

アプリからCloudFrontにアクセスする際に署名付きCookieを使用したかったので試してみた
サーバ側でCloudFrontから署名付きcookieを取得し
「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」
をアプリ側に渡している状態を前提としている

画像の場合

サンプルコード (Android)

画像リクエストにCookieを設定する画像ライブラリとしてFrescoとGlideがあったが、Glideの方がささっと実装できそうだったのでGlideを選択した

外部アクセスするのでマニフェストファイルに以下パーミッションを追加

<uses-permission android:name="android.permission.INTERNET" />
  • MainActivity.java
package com.example.makotokawano.imagetest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;
import com.bumptech.glide.load.model.LazyHeaders;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ImageView matchImage = findViewById(R.id.match_image);
    String url = "[CloudFrontコンテンツURL]";

    //cookieに「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」の
    //3パラメーターが必要
    String cookie =
        "CloudFront-Policy=" + "XXXX" + ";"
        + "CloudFront-Signature=" + "XXXX" + ";"
        + "CloudFront-Key-Pair-Id=" + "XXXX" + ";";

    Headers headers = new LazyHeaders.Builder()
        .addHeader("Cookie", cookie)
        .build();

    Glide.with(this).load(new GlideUrl(url, headers)).into(matchImage);
  }
}
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
    tools:context=".MainActivity"
    >

    <ImageView
        android:id="@+id/match_image"
        android:layout_width="200dp"
        android:layout_height="200dp" />

</LinearLayout>

サンプルコード(Swift)

UIImageViewをカスタマイズする
(参考: https://qiita.com/nbapps_dev/items/d22837b04d8bb0a3127d

import Foundation
import UIKit
class SimpleAsyncImageView: UIImageView {    
    //画像を非同期で読み込む
    func loadImage(urlString: String){

        var req = URLRequest(url: NSURL(string:urlString)! as URL)

        //cookieをセット
        let cookieValue = 
            "CloudFront-Policy=" + "XXXX" + ";"
            + "CloudFront-Signature=" + "XXXX" + ";"
            + "CloudFront-Key-Pair-Id=" + "XXXX" + ";"

        req.setValue(cookieValue, forHTTPHeaderField: "Cookie")

        let conf =  URLSessionConfiguration.default;
        let session = URLSession(configuration: conf, delegate: nil, delegateQueue: OperationQueue.main);

        session.dataTask(with: req, completionHandler:
            { (data, resp, err) in
                if((err) == nil){ //Success
                    let image = UIImage(data:data!)
                    self.image = image;

                }else{ //Error
                    print("AsyncImageView:Error \(err?.localizedDescription)");
                }
        }).resume();
    }
}

動画の場合

サンプルコード (Android)

  • MainActivity.java
package com.example.makotokawano.imagetest;

import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.VideoView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.load.model.Headers;
import com.bumptech.glide.load.model.LazyHeaders;
import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //cookieに「CloudFront-Policy」「CloudFront-Signature」「CloudFront-Key-Pair-Id」の
    //3パラメーターが必要
    String cookie =
        "CloudFront-Policy=" + "XXXX" + ";"
        + "CloudFront-Signature=" + "XXXX" + ";"
        + "CloudFront-Key-Pair-Id=" + "XXXX" + ";";

    VideoView videoView = findViewById(R.id.video_view);
    Map<String, String> videoHeaders = new HashMap<String, String>();
    videoHeaders.put("Cookie", cookie);
    videoView.setVideoURI(Uri.parse("[CloudFrontコンテンツURL]"), videoHeaders);
    videoView.setMediaController(new MediaController(this));

    videoView.start();
  }
}
  • acitivity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimaryDark"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >

    <VideoView
        android:id="@+id/video_view"
        android:layout_width="200dp"
        android:layout_height="200dp"
        />
</LinearLayout>

サンプルコード (Swift)

この辺の記事を参考にした

  • ViewController.swift
import UIKit
import AVKit
import AVFoundation
import CoreMedia

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .system)
        button.setTitle("Play", for: .normal)
        button.addTarget(self, action: #selector(self.onClick(_:)), for: .touchUpInside)

        button.sizeToFit()
        button.center = self.view.center
        self.view.addSubview(button)
    }

    @objc func onClick(_ sender: AnyObject) {
        // Do any additional setup after loading the view, typically from a nib.

        let url = URL(string: "[CloudFrontコンテンツURL]")
        let cookieStr1 = "CloudFront-Policy=" + "XXXX"
        let cookieStr2 = "CloudFront-Signature=" + "XXXX"
        let cookieStr3 = "CloudFront-Key-Pair-Id=" + "XXXX"

        let cookieHeaderField1 = ["Set-Cookie": cookieStr1]
        let cookies1 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField1, for: url!)
        let cookieHeaderField2 = ["Set-Cookie": cookieStr2]
        let cookies2 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField2, for: url!)
        let cookieHeaderField3 = ["Set-Cookie": cookieStr3]
        let cookies3 = HTTPCookie.cookies(withResponseHeaderFields: cookieHeaderField3, for: url!)
        HTTPCookieStorage.shared.setCookies(cookies1, for: url, mainDocumentURL: url)
        HTTPCookieStorage.shared.setCookies(cookies2, for: url, mainDocumentURL: url)
        HTTPCookieStorage.shared.setCookies(cookies3, for: url, mainDocumentURL: url)

        let cookiesArray = HTTPCookieStorage.shared.cookies!
        let values = HTTPCookie.requestHeaderFields(with: cookiesArray)
        let cookieArrayOptions = ["AVURLAssetHTTPHeaderFieldsKey": values]
        let assets = AVURLAsset(url: url!, options: cookieArrayOptions)
        let item = AVPlayerItem(asset: assets)
        let player = AVPlayer(playerItem: item)

        // 動画プレイヤーの用意
        let playerController = AVPlayerViewController()
        playerController.player = player
        self.present(playerController, animated: true, completion: {
            player.play()
        })
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

SetCookiesの部分が冗長的な書き方なのでもうちょっとなんとかしたい

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2