すべてのプロダクト
Search
ドキュメントセンター

Drive and Photo Service:JWT アプリケーションのアクセスプロセス

最終更新日:Jan 16, 2025

このトピックでは、JSON Web トークン (JWT) アプリケーションを使用してドライブおよびフォトサービスにアクセスするためのアクセストークンを取得する方法について説明します。

JWT アプリケーションの概要

このトピックでは、JWT アプリケーションとは、ID 認証に JWT メカニズム使用するカスタム アプリケーションのことです。

JWT アプリケーションサーバー上で秘密鍵を使用してデータに署名した後、JWT アサーションが生成されます。JWT アサーションは、公開鍵が設定されているドライブおよびフォトサービスにアクセスするための資格情報として使用されます。

image

シナリオ

  1. 企業は、独立したアカウントシステムを含む内部ソフトウェアシステムを保有しています。企業は、内部ユーザーが内部ログオンページを使用してドライブおよびフォトサービスにログオンして使用できるようにしたいと考えています。

  2. 企業は、独立したアカウントシステムを使用するログオンポータルを保有しています。企業は、ログオンポータルをドライブおよびフォトサービスに関連付けて、独立したアカウントシステムからアクセスできるクラウドストレージシステムを構築したいと考えています。

仕組み

  1. ドライブおよびフォトサービスコンソールで、カスタムドメインと JWT アプリケーションを作成します。

  2. Rivest-Shamir-Adleman (RSA) アルゴリズムを使用して、公開鍵と秘密鍵を作成します。公開鍵はドライブおよびフォトサービスサーバーに保存し、秘密鍵は JWT アプリケーションサーバーに保存します。

  3. JWT アプリケーションサーバー上で秘密鍵を使用してデータをエンコードし、署名すると、JWT アサーションが生成されます。次に、JWT アサーションはドライブおよびフォトサービスに送信されます。

  4. ドライブおよびフォトサービスは、公開鍵を使用して JWT アサーションが有効であることを確認した後、JWT アプリケーションサーバーにアクセストークンを返します。JWT アプリケーションサーバーは、アクセストークンを使用してドライブおよびフォトサービスの API オペレーションを呼び出すことができます。

手順

1. キーペアを設定する

1.1 ドメインを作成するか、既存のドメインを選択する

a1

1.2 アプリケーションを作成するか、既存のアプリケーションを選択する

ドメイン名をクリックして詳細ページに移動します。表示されるページで、[アプリケーション] タブをクリックします。[アプリケーション] タブで、JWT アプリケーションを作成するか、既存の JWT アプリケーションを選択します。

k1

1.3 公開鍵を設定する

管理する JWT アプリケーションを見つけ、[アクション] 列の [公開鍵の設定] をクリックします。

k3

公開鍵と秘密鍵のペアを生成します。k5

キーペアが生成されたら、秘密鍵をコピーして安全に保管します。[OK] をクリックします。

k4

2. アクセストークンを取得する

2.1 JWT アプリケーションサーバーから JWT アサーションを取得する

JWT アプリケーションサーバー上でデータをエンコードし、コピーした秘密鍵を使用して指定された暗号化アルゴリズムに基づいてデータに署名すると、JWT アサーションが生成されます。次の Node.js サンプルコードは、JWT アサーションを取得する方法を示しています。

const JWT = require('jsonwebtoken');

function signAssertion({ domain_id, client_id, user_id, privateKeyPEM }) {
  var now_sec = parseInt(Date.now() / 1000);
  var opt = {
    iss: client_id,
    sub: user_id,
    sub_type: "user",
    aud: domain_id,
    jti: Math.random().toString(36).substring(2),
    exp: now_sec + 60,
    // iat: now_sec, // 発行時刻
    // nbf: '', // 利用開始時刻
    auto_create: false,
  };
  return JWT.sign(opt, privateKeyPEM, {
    algorithm: "RS256",
  });
}

opt パラメーター

パラメーター

必須

タイプ

説明

iss

はい

文字列

JWT アプリケーションの ID。

sub

はい

文字列

ユーザーまたはドメインの ID。

sub_type (拡張フィールド)

はい

文字列

アカウントのタイプ。有効な値:user および service。user の値は、sub パラメーターがユーザーの ID に設定されており、次のステップで通常のユーザーのアクセストークンが発行されることを示します。service の値は、sub パラメーターがドメインの ID に設定されており、次のステップでサービスアカウントのアクセストークンが発行されることを示します。これにより、サービスアカウントはスーパー管理者としてドライブおよびフォトサービスにアクセスできます。

aud

はい

文字列

ドメインの ID。

jti

はい

文字列

JWT アサーションの一意の識別子。識別子は 16~128 バイトの長さである必要があります。このパラメーターを UUID に設定することをお勧めします。

exp

はい

整数

JWT アサーションの有効期限。このパラメーターは UNIX タイムスタンプ形式で指定します。単位:秒。JWT アサーションの有効期間は 15 分を超えることはできません。クライアントの時刻とサーバーの時刻に不整合が生じる場合に備えて、このパラメーターを現在の時刻から 5 分後に設定することをお勧めします。

iat

いいえ

整数

JWT アサーションが発行された時刻。この時刻より前は JWT アサーションを使用できません。このパラメーターは UNIX タイムスタンプ形式で指定します。単位:秒。例:1577682075。

nbf

いいえ

整数

JWT アサーションの有効時刻。このパラメーターは UNIX タイムスタンプ形式で指定します。単位:秒。デフォルトでは、このパラメーターを指定しない場合、現在の時刻が使用されます。JWT アサーションの有効期間は 15 分を超えることはできません。クライアントの時刻とサーバーの時刻に不整合が生じる場合に備えて、このパラメーターを現在の時刻の 5 分前に設定するか、このパラメーターを指定しないことをお勧めします。

auto_create (拡張フィールド)

いいえ

ブール値

指定したユーザーが存在しない場合にユーザーを自動的に作成するかどうかを指定します。デフォルトでは、システムはユーザーを自動的に作成しません。

JWT のサードパーティライブラリと暗号化アルゴリズムの詳細については、JWT 公式 Web サイトをご覧ください。

2.2 JWT アサーションをアクセストークンと交換する

認証オペレーションを呼び出して JWT アサーションをアクセストークンと交換する方法のサンプルコードを以下に示します。

POST /v2/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=${APP_ID}&assertion=xxxxxxxxxx
説明

注:Content-Type ヘッダーを application/x-www-form-urlencoded に設定し、リクエストボディにリクエストパラメーターを指定します。

リクエストパラメーター

パラメーター

必須

タイプ

説明

grant_type

はい

文字列

認証のタイプ。値を urn:ietf:params:oauth:grant-type:jwt-bearer に設定します。

client_id

はい

文字列

アプリケーションの ID。

assertion

はい

文字列

前のステップで生成された JWT アサーション。

JSON 形式のアクセストークンの例

{
  "access_token": "eyJh****eQdnUTsEk4",
  "refresh_token": "kL***Lt",
  "expires_in": 7200,
  "token_type": "Bearer"
}

JWT アプリケーションサーバーがアクセストークンを取得した後、アクセストークンは JWT Web サーバーに送信されます。JWT Web サーバーは、アクセストークンを使用してドライブおよびフォトサービスの API オペレーションを呼び出し、ドライブおよびフォトサービスに保存されているリソースにアクセスできます。

2.3 アクセストークンを更新する

JWT アプリケーションを使用して取得したアクセストークンは、2 時間のみ有効です。アクセストークンの有効期限が切れたら、手順 2.1 と 2.2 を実行して新しいアクセストークンを取得できます。7 日以内であれば、ドライブおよびフォトサービスの API オペレーションを呼び出してアクセストークンを更新することもできます。7 日後には、手順 2.1 と 2.2 に従って新しいアクセストークンを取得する必要があります。

認証オペレーションを呼び出してアクセストークンを更新する方法のサンプルコードを以下に示します。

POST /v2/oauth/token
Content-Type: application/x-www-form-urlencoded

client_id=${APPID}&refresh_token=${access_token}&grant_type=refresh_token&redirect_uri=${REDIRECT_URI}

パラメーター

必須

タイプ

説明

client_id

はい

文字列

アプリケーションの ID。

refresh_token

はい

文字列

有効期限が切れたアクセストークン。

grant_type

はい

文字列

認証のタイプ。値を refresh_token に設定します。

redirect_uri

はい

文字列

アプリケーションに設定したリダイレクト URI。

(オプション) 3. ドライブおよびフォトサービスの基本 UI を使用する

ユーザーインターフェース (UI) を開発したくない場合、ドライブおよびフォトサービスが提供する基本 UI でビジネス要件を満たせる場合は、基本 UI を使用できます。

方法 1:

window.open() メソッドを使用して基本 UI を開き、postMessage() メソッドを使用してアクセストークンを渡します。

例:

const endpoint = `https://${domain_id}.apps.aliyunpds.com`
const url = `${endpoint}/accesstoken?origin=${location.origin}`
var win = window.open(url)

window.addEventListener('message', onMessage, false)
async function onMessage(e) {
  if (e.data.code == 'token' && e.data.message == 'ready') {
    var result = await getToken();// JWT アプリケーションサーバーからアクセストークンを取得します。
    //result = {"access_token": ...}
    win.postMessage({
      code: 'token',
      message: result
    }, endpoint || '*')

    window.removeEventListener('message', onMessage)
  }
}

方法 2:

iframe を使用して基本 UI を埋め込み、postMessage() メソッドを使用してアクセストークンを渡します。

例:

const endpoint = `https://${domain_id}.apps.aliyunpds.com`
// iframe を使用して、ホストページに基本 UI を埋め込みます。
const iframeURL = `${endpoint}/accesstoken?origin=${location.origin}`

HTML の例:

// iframeURL 変数を指定します。
<iframe id="ifr" src="iframeURL"></iframe>
window.addEventListener('message', onMessage)
async function onMessage(e) {
  if (e.data.code == 'token' && e.data.message == 'ready') {
    var result = await getToken();// JWT アプリケーションサーバーからアクセストークンを取得します。
    //result = {"access_token": ......}
    document.getElementById('ifr').contentWindow.postMessage({
        code: 'token',
        message: result
    }, endpoint || '*')

    window.removeEventListener('message', onMessage)
  }
}
説明

注:方法 2 を使用するには、基本 UI のセキュリティ設定でホストページのオリジンを設定する必要があります。

たとえば、ホストページの URL が https://example.com/a.html の場合、ホストページのオリジンは https://example.com です。この場合、次の図に示すように、example.com と入力します。

image

方法 3:

iframe を使用して、カスタムログオンページに基本 UI を埋め込みます。

カスタムログオンページの URL と JWT アプリケーションの ID を指定します。その後、基本 UI でアクセストークンが自動的に更新されます。

image

ログオンリクエストが送信されると、基本 UI のデフォルトのログオンページではなく、カスタムログオンページが表示されます。

ユーザーがシステムにログオンすると、基本 UI は postMessage() メソッドを使用してアクセストークンをカスタムログオンページに渡します。

image

if(parent!=self){
  let origin = ''
  parent.postMessage({
    code: 'token',
    message: {
       access_token: 'xxxx',
       refresh_token: 'xxxx',
       ...
    }
  }, endpoint || "*")
}

付録 1:Node.js のサンプルコード

次のサンプルコードは、JWT アプリケーションを使用してアクセストークンを取得する方法と、アクセストークンを更新する方法を示しています。

const fs = require('fs')
const JWT = require('jsonwebtoken');
const axios = require('axios')

const DOMAIN_ID = '' // ドメイン ID。
const APP_ID = '' // JWT アプリケーションの ID。
const USER_ID = '' // ユーザー ID。
const PRIVATE_KEY_PEM = '' // 秘密鍵。手順 1.3 で取得します。
const PRE = `https://${DOMAIN_ID}.api.aliyunpds.com`

async function init() {
  try {
    // ビジネス要件に基づいて、次の変数を指定します。
    var params = {
      domain_id: DOMAIN_ID,
      client_id: APP_ID,
      user_id: USER_ID,
      privateKeyPEM: PRIVATE_KEY_PEM,
    };
    var assertion = signAssertion(params)
    var obj = await getToken(assertion)
    return obj.data
  } catch (e) {
    if (e.response) {
      console.log(e.response.status)
      console.log(e.response.headers)
      console.log(e.response.data)
    } else {
      console.error(e)
    }
  }
}

function signAssertion({ domain_id, client_id, user_id, privateKeyPEM }) {
  var now_sec = parseInt(Date.now()/1000)
  var opt = {
    iss: client_id,
    sub: user_id,
    sub_type: 'user',
    aud: domain_id,
    jti: Math.random().toString(36).substring(2),
    exp: now_sec + 300,
    // iat: now_sec, // 発行時刻
    // nbf: '', // 利用開始時刻
    auto_create: true,
  };
  return JWT.sign(opt, privateKeyPEM, {
    algorithm: 'RS256'
  });
}

async function getToken(assertion) {
  return await axios({
    method: 'post',
    url: PRE + '/v2/oauth/token',
    // 注:Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    // 注:リクエストボディにリクエストパラメーターを指定します。
    data: params({
      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      client_id: APP_ID,
      assertion
    })
  })
}

async function refreshToken(refresh_token) {
  return await axios({
    method: 'post',
    url: PRE + '/v2/oauth/token',
    // 注:Content-Type ヘッダーを application/x-www-form-urlencoded に設定します。
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    // 注:リクエストボディにリクエストパラメーターを指定します。
    data: params({
      grant_type: 'refresh_token',
      client_id: APP_ID,
      refresh_token,
    })
  })
}

function params(m){
  const params = new URLSearchParams();
  for(var k in m){ 
     params.append(k, m[k]);
  }
  return params;
}

// テストコール。
;(async ()=>{
  let result = await init() 
  console.log(result) // {access_token:...} 構造でアクセストークンを返します。アクセストークンの構造の詳細については、このトピックの付録 2 を参照してください。
  // アクセストークンの有効期限が切れたら、アクセストークンを更新します。
  refreshToken(result.refreshToken) // {access_token:...} 構造で新しいアクセストークンを返します。アクセストークンの構造の詳細については、このトピックの付録 2 を参照してください。
})();

付録 2:アクセストークンの構造

例:

{
  access_token: 'eyJhbG.....g7M0p28',
  refresh_token: '62f1acc.......9b781f3',
  expires_in: 7200,
  token_type: 'Bearer',
  ......
}