概要
KollusモバイルダウンロードDRMを利用してダウンロードしたコンテンツの「再生回数」、「再生有効期限」、「再生時間」を設定してコンテンツの再生を制御する機能について説明する文書です。サービス提供形態によって重複制限の設定として使用されることもあります。
Expire option
設定項目のdata-typeや値が範囲から外れた場合、エンドユーザーのコンテンツの利用に問題が発生する可能性があります。また、誤った設定値による使用回数の過剰などを回収する方法はありませんので設定に注意してください。
Expire date : 有効期限の制限
data-type : integer, unixtime stamp
コンテンツの有効期限(再生可能期限)
終了日(日時)
例) 2014. 3. 3. 5時 45分 30秒 GMT → 1393825531
最大値 : 2029年 12月 31日 23時 59分 59秒 (1893455999)
Expire playtime : 再生時間(倍速再生の場合は倍速が適用された時間で計算)
range : 0, 60 ~ 604800 (単位: 秒, min : 60秒, max:1週間)
DRM callback
DRM ポリシーを適用するためには、チャンネルにDRM Callback URLを設定する必要があります。
チャンネルにDRM Callback URLを設定すると、コンテンツをダウンロードする時点にDRM Callback URLを呼び出して、リターン値をDRMポリシーとして使用します。ダウンロードされるDRMポリシー情報はJWT EncodeされてHttp Bodyにリターンしなければなりません。
注意:
DRM Callback URLがレスポンスしないとダウンロードできません。
アルゴリズムはHS256のみ対応しており、Httpヘッダに指定された(X-KOLLUS-USERKEY)ヘッダに“ユーザーキー”を共に転送しなければなりません。
Callback flow
配信チャンネルに DRM CallbackURLを設定します。
Kollus mobile playerがhttp://www.foo.com/auth.php に以下の情報をPOST転送します。
session_key : Playerが生成したリクエスト確認用のセッションキー
kind3のcontent_expire_resetの場合、リクエストしたsession_keyを確認します。
Callback v2が適用されるv1.6以降から使用可能です。
client_user_id : ユーザID(サービス会員情報)
device_name : ユーザのデバイス名
Android, iOS別に転送される端末名が異なります。
iOS:事前にApple社が定義した文字列で転送されます。
Android:デバイス名、モデル名が転送されます。※該当する情報がない場合NULLで転送
media_content_key : ダウンロードするコンテンツキー
チャンネルに登録されたコンテンツのメディアコンテンツキー(ユニーク)
同じコンテンツを複数のチャンネルに登録する場合、それぞれのmedia_content_keyは全て異なります。
顧客のDRM認証サーバーは転送された上記の情報に基づいて以下のjson フォーマットのdataをJWT payloadに追加してEncoding します。ヘッダーに指定された“ユーザキー(X-KOLLUS-USERKEY)"を一緒に転送します。
(顧客が認証データをPlayerに転送する全てのデータは必ずinteger型で転送しなければなりません。)
device_name 追加説明
Andoid
Androidアプリケーションの開発に使用される Build.DEVICE, Build.MODELは /(スラッシュ)で区分した文字列を作成して使用してください。
Build.DEVICE+”/”+Build.MODEL
デバイスによって該当情報はNULLで表示される可能性があります。
iOS
iOSから提供するdevice-nameを使用します。
DRM Callback新規バージョン v2
バージョン1.4まで提供していた「kind1, kind2, kind3」の個別で呼び出しを行われたことを、一回の呼出で統合しました。ユーザー側の呼出が増えることで対応が難しいとの多数の顧客からの意見に対応しました。新しいバージョンを"v2"で、以前バージョンを"v1"で記載します。
Reuest
items項目はkind1, kind2, kind3の全てのデータが含まれた呼出にすることができます。
items (JsonArray)
kind1, kind2
kind3
Items Sample
[
{
"kind": 1,
"media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
"client_user_id": "XXXXXXX",
"player_id": "xxxxxxxxxxxxxxxx",
"device_name": "XXXXX",
"uservalues": {
"uservalue0": "value0"
}
},
{
"kind": 2,
"media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
"client_user_id": "XXXXXXX",
"player_id": "xxxxxxxxxxxxxxxx",
"device_name": "XXXXX",
"uservalues": {
"uservalue0": "value0"
}
},
{
"kind": 3,
"session_key" : "XXX-SESSION_KEY-XXX", ← content_expire_reset リクエストする際に確認します。
"media_content_key" : "XXX-MEDIA_CONTENTKEY-XXX",
"client_user_id": "XXXXXXX",
"player_id": "xxxxxxxxxxxxxxxx",
"device_name": "XXXXX",
"uservalues": {
"uservalue1": "value1"
}
}
]
Response
Arrayは“data”フィールドで受け取る
kind1
kind2
kind3
Response Example
{
“data” : [
{
"kind": 1,
"media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
"expiration_date": 1402444800,
"expiration_count": 10,
"expiration_playtime": 60,
"result": 1
},
{
"kind": 2,
"media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
"content_delete": 1,
"result": 1
},
{
"kind": 3,
"session_key" : "XXX-SESSION_KEY-XXX",
"media_content_key": "XXX-MEDIA_CONTENT_KEY-XXX",
"start_at": 140000000,
"content_expired": 1,
"content_delete": 1,
"content_expire_reset": 1,
"expiration_date": 1402444800,
"expiration_count": 10,
"expiration_playtime": 3600,
"result": 1
}
]
}
JWT 対応
DRMポリシーをJWTでレスポンスすることができます。JWT ウェブサイト(https://jwt.io) から公認されたライブラリーを使用して生成されたTokenに変更してレスポンスする機能が追加されました。
PlayerにJWT Tokenで返還する場合には指定されたヘッダにユーザーキーを含めて転送しなければなりません。
HTTP/1.1 200 OK
Date: Fri, 14 Oct 2016 04:12:46 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Kollus-UserKey: 0993d76eb424a72f2005b874ac49405d44a6c
Content-Encoding: gzip
指定した(X-Kollus-UserKey) ヘッダに転送されたユーザーキーの情報が一致する場合のみ再生されます。
JWT Secret, JWT ユーザーキー
ユーザーキー(2)をheaderに追加することと共に、既存のJWT scpecにあるsecret keyにはセキュリティキー(1)を入力しなければなりません。Kollus CMSで以下のように関連情報を確認することができます。
設定 > サービスアカウント設定
JWT payload
各 callbackの responseを JWT playloadに入れて転送します。
Sample
http://jwt.io から提供している様々な言語で具現されたライブラリーとサンプルを使用してください。JWT スペックと同じですが、レスポンスされるhttpヘッダに X-Kollus-UserKeyでユーザーキーを一緒に転送しなければなりません。
(サンプル) php
define('KOLLUS_KEY', '**ユーザーキー**'); // X-Kollus-UserKey
define('JWT_KEY', '**セキュリティキー**'); // JWT VERIFY SIGNATURE
function encode_jwt($payload, $key, $alg = 'HS256') {
$header = array('alg' => $alg, 'typ' => 'JWT' );
$unsignedToken = base64_encode(json_encode($header)).'.'.
base64_encode(json_encode($payload));
$signature = hash_hmac('sha256', $unsignedToken, $key, TRUE);
return $unsignedToken.'.'.base64_encode($signature);
}
$payload = array(
'data' => array(
array(
'kind' => 1,
'result' =>1,
'expiration_date' => time()+3600,
'expiration_playtime' => 30,
'vmcheck' => 1,
),
array(
'kind' => 2,
'result' =>1,
'expiration_date' => time()+3600,
'expiration_playtime' => 30,
'vmcheck' => 1,
),
array(
'kind' => 3,
'result' =>1,
'expiration_date' => time()+3600,
'expiration_playtime' => 30,
'vmcheck' => 1,
),
),
);
$result = encode_jwt($payload, JWT_KEY);
//header('Content-Type: application/jwt');
header('X-Kollus-UserKey: '.KOLLUS_KEY);
echo $result;
Code sample (v1.4 基準)
以下のように顧客のDBが構成されたことを想定したサンプルコードになります。
PHP sample
<?php
/**
* PHP Version : 5.4 above
*/
function get_jwt($payload, $key, $alg = 'HS256')
{
$header = array('alg' => $alg, 'typ' => 'JWT' );
$unsignedToken = base64_encode(json_encode($header)).'.'.base64_encode(json_encode($payload));
$signature = hash_hmac('sha256', $unsignedToken, $key, TRUE);
return $unsignedToken.'.'.base64_encode($signature);
}
function print_kollus_jwt($data)
{
define('KOLLUS_KEY', '**ユーザーキー**'); // X-Kollus-UserKey
define('JWT_KEY', '**セキュリティキー**'); // JWT VERIFY SIGNATURE
$payload = array( ‘data’ => $data );
$result = encode_jwt($payload, JWT_KEY);
//header('Content-Type: application/jwt');
header('X-Kollus-UserKey: '.KOLLUS_KEY);
echo $result;
}
/////////////////////////////////////////////////
include "./config.php";
// 注意 : kindが1の場合、自動でexpiration_dateが生成されるサンプルページとなります。
// 再生回数制限値
$_default_expiration_count = 3;
$_expired_duration = 60 * 60 * 24; // 1 day
// DB Connection
$_db_conn = mysqli_connect($_hostname, $_username, $_password);
if (!$_db_conn) {
die('Could not connect: ' . mysql_error());
}
$_db_selected = mysqli_select_db($_database, $_db_conn);
if (!$_db_selected) {
die ('Can\'t use database : ' . mysqli_error());
}
$_kind = isset($_POST['kind']) ? ((int) $_POST['kind']) : NULL;
$_media_content_key = isset($_POST['media_content_key']) ? $_POST['media_content_key'] : NULL;
$_client_user_id = isset($_POST['client_user_id']) ? $_POST['client_user_id'] : NULL;
$channel = NULL;
$_query = sprintf("SELECT * FROM `channels` WHERE `media_content_key` = '%s'",
mysqli_real_escape_string($_media_content_key, $_db_conn));
$_result = mysqli_query($_query, $_db_conn);
if ($_result) {
$channel = mysqli_fetch_array($_result, MYSQL_ASSOC);
if ($channel === FALSE) $channel = NULL;
} else {
die('Invalid query: ' . mysqli_error());
}
$user = NULL;
$_query = sprintf("SELECT * FROM `users` WHERE `client_user_id` = '%s'",
mysqli_real_escape_string($_client_user_id, $_db_conn));
$_result = mysqli_query($_query, $_db_conn);
if ($_result) {
$user = mysqli_fetch_array($_result, MYSQL_ASSOC);
if ($user === FALSE) $user = NULL;
} else {
die('Invalid query: ' . mysqli_error());
}
$channel_user = NULL;
if (!is_null($_media_content_key) && !is_null($_client_user_id)) {
$_query = sprintf("SELECT * FROM `channel_users` WHERE `user_id` = '%s', `channel_id` = '%s'", $user['id'], $channel['id']);
$_result = mysqli_query($_query, $_db_conn);
if ($_result) {
$channel_user = mysqli_fetch_array($_result, MYSQL_ASSOC);
if ($channel_user === FALSE) $channel_user = NULL;
} else {
die('Invalid query: ' . mysqli_error());
}
}
$_jwt_result = array('result' => 0);
switch($_kind) {
case 1:
if (is_null($channel_user)){
$_expiration_date = time() + $_expired_duration;
$_expiration_count = $_default_expiration_count;
$_query = sprintf("INSERT INTO `channel_users`(`user_id`, `channel_id`, `expiration_date`
,`expiration_count` , `created_at`, `updated_at`) VALUES('%s', '%s', '%s', '%s', UNIX_TIMESTAMP(),
UNIX_TIMESTAMP())", $user['id'], $channel['id'], $_expiration_date, $_expiration_count);
$_result = mysqli_query($_query, $_db_conn);
if (!$_result) {
die('Invalid query: ' . mysqli_error());
}
} else {
$_expiration_date = $channel_user['expiration_date'];
$_expiration_count = $channel_user['$expiration_count'];
}
$_jwt_result['expiration_date'] = (int) $_expiration_date;
$_jwt_result['expiration_count'] = (int) $_expiration_count;
break;
case 2:
if (!is_null($channel_user)){
$_download_times = ++((int) $channel_user['download_times']);
$_query = sprintf("UPDATE `channel_users` SET `download_times` = '%s', `updated_at` =
UNIX_TIMESTAMP() WHERE id = %s", $_download_times, $channel_user['id']);
$_result = mysqli_query($_query, $_db_conn);
if (!$_result) {
die('Invalid query: ' . mysql_error());
}
$_jwt_result['result'] = 1;
}
break;
case 3:
if (!is_null($channel_user) && $channel_user['is_expired']) {
$_jwt_result['content_expired'] = 1;
}
break;
}
// DB Close
mysqli_close($_db_conn);
// 結果の data arrayをJWTに変換して出力
print_kollus_jwt($_jwt_result);
サービスサポート
サンプルコードについてのお問い合わせは担当までご連絡ください。
E-mail お問い合わせ > jp_team@catenoid.net
電話番号 > 03-4405-8462
Last updated