開発:OAuth 2 API

提供:MoodleDocs
2023年3月2日 (木) 15:02時点におけるMitsuhiro Yoshida (トーク | 投稿記録)による版
移動先:案内検索

OAuth 2 API

Moodle 3.3


作成中です - Mitsuhiro Yoshida (トーク)

OAuth 2 APIはリモートシステムとの統合のためのOAuth 2機能を提供するクラス群です。これらは「/lib/classes/oauth2/」フォルダに存在します。また注意すべきいくつかのコンセプトがあります。

イシュア

OAuthイシュアとはOAuthアクセストークンを発行してIDおよびAPIアクセスを提供する名前付きの外部システムです。これらは「サイト管理 -> サーバ -> OAuth 2サービス」で手動設定できます。一般的なOAuthアクセストークンはテンプレート (Google、Office 365、Facebook) からすぐに作成できます。イシュアは名前およびアイコン(ログインページに表示)、クライアントIDおよびクライアントシークレット (OAuth仕様の一部) を持ちます。

エンドポイント

OAuth発行者はアクセストークンの取得および交換、ID情報の取得に使用するURLであるいくつかのエンドポイントを定義しておく必要があります。テンプレートから作成したOAuthサービスおよびOpen ID Connectを使ったOAuthサービスではこれらは自動的に設定されます。

定義すべき標準的なエンドポイントは「認証エンドポイント」「トークンエンドポイント」「ユーザ情報エンドポイント」の3つです。これはOAuthプロトコルによって「ユーザのログインを許可」「APIにアクセスするためのトークンを取得」「ログインしたユーザ情報を取得」するための3つのURLとなります。

Open ID Connect

Open ID ConnectはOAuth 2の上に構築されたプロトコルであり、OAuth 2ベースのサービスに標準化および相互運用性を提供します。もし「基本サービスURL」が発行者に入力された場合、Moodleはこのサービスの設定を完了するために必要な他のエンドポイントに関するすべての情報を提供する「よく知られた設定」を取得するよう試みます。例) Googleの場合 - 基本サービスのURLは「https://accounts.google.com/」です。このURLに「.well-known/openid-configuration」 を付加してhttps://accounts.google.com/.well-known/openid-configurationにあるサービス説明文を閲覧できます。説明文にはこのサービスの設定を自動的に完了させるために必要な情報すべてを含みます。これはOpen ID connectに準拠したサービスであればどれでも動作します。

Open Badge Connect API

Open Badge Connect APIはIMS Global社により策定されたOAuth 2ベースサービスの標準化および相互運用性を提供するための仕様です。イシュアに「基本サービスURL」が入力された場合、Moodleはこのサービスの設定を完了するために必要なエンドポイントに関するすべての情報を提供する「よく知られた設定」(well-known/badgeconnect.json) を取得するよう試みます。さらにクライアントIDおよびシークレットが与えられていない場合、それらを取得するために登録エンドポイントがコールされます (そして管理者に安全な時間および労力を提供します)。 例) IMS Globalテストプラットフォームの場合、基本サービスのURLは「https://dc.imsglobal.org/」です。私たちはこのURLに「.well-known/badgeconnect.json」を追加してこのサービスのセットアップを自動的に完了するために必要なすべての情報 (エンドポイント、クライアントIDと秘密、画像...) を含むサービスの説明を確認できます。

ユーザフィールドマッピング

OAuth 2サービスに関して私たちが知るべき他の情報はユーザ情報をMoodleのユーザフィールドにマッピングする方法です。これは発行者用のユーザフィールドマッピングのリストにユーザ情報を追加することによりマッピングします。Open ID Connectサービス用のマッピングは標準的なもので Open ID に準拠したサービスをセットアップする際に自動作成されます。新しいアカウントを作成する場合、Moodleはユーザプロファイルのフィールドをインポートするためにこの情報を使用します。最も重要なユーザフィールドのマッピングはOAuth 2ログインに関連するMoodleアカウントを識別するために使用されるユーザ名およびメールアドレスです。


新しいイシュアサービスをどのように実装するのか?

いかなるOAuth2サービスにおいてもlib/classes/oauth2/service/フォルダにdiscoveryシステムから拡張されたクラス (core\oauth2\discovery\base_definition) およびcore\oauth2\service\issuer_interfaceの実装が必要です:

  • ディスカバリシステムではエンドポイントを取得する方法を示します。
  • イシュアインターフェースにはいくつかの共通メソッドがあり、エンドポイントを初期化または発見するためlib/classes/oauth2/api.phpからコールされます。
class google extends openidconnect implements issuer_interface {
[...]

class imsobv2p1 extends imsbadgeconnect implements issuer_interface {
[...]


OAuth 2イシュアを設定しました - コード内でどのように使えばよいですか? I set up an OAuth 2 Issuer - how do I use it in code?

OAuthイシュアが提供する設定情報を利用したいプラグインはまずどのイシュアを利用して認証するか決定する必要があります。これは通常、管理者が設定されたイシュアのリストから選択できるようにする設定追加で実現されます。例えば「Google Drive」リポジトリのようなものです。似たようなOAuthイシュアを複数設定することも可能です。例えば公開されているGoogleのイシュアおよび特定のドメインに限定されたイシュアがあります。使用したいイシュアが分かった場合、私たちはそのIDを使用してAPIに対してリクエストできるイシュアクラス (IssuerClient) を取得できます。

// IDからイシュアを取得します。
$issuer = \core\oauth2\api::get_issuer($issuerid);
// イシュアからOAuthクライアントを取得します。
$client = \core\oauth2\api::get_user_oauth_client($this->issuer, $returnurl, $scopes);

コードドキュメントに書かれている内容に拘わらず、クライアントが認証されているかどうかを確認して、認証されていない場合はログインするようユーザをリダイレクトするのがベストです。

if (!$client->is_logged_in()) {
    redirect($client->get_login_url());
}

リターンURLとは何ですか? What is return URL?

これはあなたを現在のページから元のページに戻すためのURLです。OAuthの仕組みはOAuthクライアントを取得するための呼び出しで私たちに必要なスコープをすべて持つ有効なセッションがあるかどうか確認するというものです。私たちにセッションがない場合、直ちにOAuthログインページにリダイレクトされます。ログインした場合、Moodleの「returnurl」にリダイレクトされてOAuthクライアントを取得するために同じ呼び出しが実行されます - 今回は有効なセッションがあるため、クライアントが返されます。returnurlにはパラメータの1つとしてsesskeyを含む必要があります。

スコープとは何ですか?

これは「パーミッショングラント」(パーミッション許可) と名付けられユーザは承諾を求められます。 例えば「email」はあなたがログインしているアカウントのメールアドレスをMoodleが確認できるようにするスコープです。要求された各パーミッションはその意味の説明とともにユーザに表示されるため、ユーザはMoodleにこのレベルのアクセスを「許可」にする必要があります - 許可しない場合は操作をキャンセルしてください。一度に必要以上のスコープを要求せずにMoodleの異なる機能で使用されそうなスコープを段階的に追加要求することが最良の方法です。例えばMoodleにログインする場合、私たちはユーザの基本プロファイルおよびメールアドレスへのアクセスを要求する必要があるだけです。リポジトリにアクセスする場合 - 私たちはユーザのファイルへの読み込み/書き込みアクセスを要求する必要があります。私たちはoauthクライアントクラスを作成する度にoauthクライアントインスタンスで使用するスコープをリストアップします。もしユーザが要求したスコープの一部しか承認しない場合、追加アクセスレベルを承認するための同意画面にリダイレクトされます。

それで、oauthクライアントで何ができますか?

リクエストを作成しましょう! このクラスはmoodle curlクラスを継承していますが、各リクエストに自動的に認証情報を含めます。これは$client->get()または$client->post()のような標準関数を使って手動で残りのAPI関数を呼び出せることを意味します。またこのクラスはIPアドレスブラックリストおよびプロキシ設定のような設定済みMoodleセキュリティ設定を尊重します。

API関数を簡単に呼び出すには?

外部のrest apiを使いやすくラップするためのヘルパ関数が含まれた抽象クラス\coreauth2restが存在します。使用するには自分のプラグインでサブクラスを作成して、「get_api_functions()」メソッドを定義してください。

/**                                                                                                                                 
 * Google Drive Rest API.                                                                                                           
 *                                                                                                                                  
 * @package    fileconverter_googledrive                                                                                            
 * @copyright  2017 Damyon Wiese                                                                                                    
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later                                                             
 */                                                                                                                                 
namespace fileconverter_googledrive;                                                                                                
                                                                                                                                    
defined('MOODLE_INTERNAL') || die();                                                                                                
                                                                                                                                    
/**                                                                                                                                 
 * Google Drive Rest API.                                                                                                           
 *                                                                                                                                  
 * @copyright  2017 Damyon Wiese                                                                                                    
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later                                                             
 */                                                                                                                                 
class rest extends \core\oauth2\rest {                                                                                              
                                                                                                                                    
    /**                                                                                                                             
     * Define the functions of the rest API.                                                                                        
     *                                                                                                                              
     * @return array Example:                                                                                                       
     *  [ 'listFiles' => [ 'method' => 'get', 'endpoint' => 'http://...', 'args' => [ 'folder' => PARAM_STRING ] ] ]                
     */                                                                                                                             
    public function get_api_functions() {                                                                                           
        return [                                                                                                                    
            'create' => [                                                                                                           
                'endpoint' => 'https://www.googleapis.com/drive/v3/files',                                                          
                'method' => 'post',                                                                                                 
                'args' => [                                                                                                         
                    'fields' => PARAM_RAW                                                                                           
                ],                                                                                                                  
                'response' => 'json'                                                                                                
            ],                                                                                                                      
            'delete' => [                                                                                                           
                'endpoint' => 'https://www.googleapis.com/drive/v3/files/{fileid}',                                                 
                'method' => 'delete',                                                                                               
                'args' => [                                                                                                         
                    'fileid' => PARAM_RAW                                                                                           
                ],                                                                                                                  
                'response' => 'json'                                                                                                
            ],                                                                                                                      
        ];                                                                                                                          
    }                                                                                                                               
}

この例では外部APIに「create」および「delete」の2つの関数を定義しています。これらの関数を呼び出す際に使用するhttpメソッドおよびパラメータのリストを指定します。また、これらの関数が「json」を返すことも指定しています。 これはRESTクラスがjsonレスポンスを自動的にデコードしてオブジェクトに変換することを意味します。各関数の呼び出しURLにはパラメータを含めることができます (中括弧でマークされています)。これらは関数に引数として渡される際に置き換えられます。残りの引数はクエリパラメータとして追加されます。

To use this class - we pass the oauth2 client to the constructor and then use the "call" method to call functions from the api.このクラスを使うには - 私たちはコンストラクタにoauth2クライアントを渡した後、「call」メソッドを使ってAPIから関数を呼び出します。


$service = new \fileconverter_googledrive\rest($client);           

$params = ['fileid' => $fileid];                                                                                                                          

$service->call('delete', $params);

How do I call API functions when the user is not logged in (e.g. from a scheduled task)?

Moodle allows you to connect a "system account" to any of the OAuth issuers. This is optional - so before enabling functionality that relies on this level of access you should check that the system account has been connected:

if ($issuer->is_system_account_connected()) {
    // Rock and roll.
}

If a system account has been connected - we can use it to get an authenticated oauth client (no redirects involved).

$client = \core\oauth2\api::get_system_oauth_client($issuer);

This client can now be used to access apis as the Moodle system user.

If your code is going to use additional login scopes with this API - it must list all of the scopes it will use in a callback function so that the Moodle administrator can consent and agree to all the scopes when they connect the system account.

**                                                                                                                                 
 * Callback to get the required scopes for system account.                                                                          
 *                                                                                                                                  
 * @param \core\oauth2\issuer $issuer                                                                                               
 * @return string                                                                                                                   
 */                                                                                                                                 
function fileconverter_googledrive_oauth2_system_scopes(\core\oauth2\issuer $issuer) {                                              
    if ($issuer->get('id') == get_config('fileconverter_googledrive', 'issuerid')) {                                                
        return 'https://www.googleapis.com/auth/drive';                                                                             
    }                                                                                                                               
    return '';                                                                                                                      
}

The way the system account works is that a Moodle admin "connects" the system account by logging in with this account and accepting the permissions from the "Site administration -> Server -> OAuth 2 Services" page. One of the permissions they must accept is for offline access. This means that Moodle will receive a refresh token and can store it against that issuer. When we need to get a logged in OAuth client - we can exchange the refresh token for an access token directly, without having to login. The refresh token is updated by a scheduled task to make sure it never expires.