WEB/システム/IT技術ブログ

LaravelでPassportパッケージ(OAuth2)を使用したAPI認証を構築

Laravelを使った認証方法をいくつかあるようですが、Passportパッケージを使ったAPI認証の構築にチャレンジしてみます。

今回は、Facebook APIやTwitter APIのようなAPIを介してサービスを提供する側の認証や、vue.jsなどWebアプリを構築する際にサーバサイドへのアクセスに認証を設けるケースを想定します。

ちなみに、構築した環境は以下の通りです。

  • Windows 11 Home
  • PHP 7.3.33
  • Laravel 6.20.44

Passportパッケージをインストールと設定

Composerを使ってPassportパッケージをインストールします。私の場合、Laravel 6.xが最新のpassport 10.xに対応していないようだったので、一つバージョンを落としてインストールしました。

> composer require laravel/passport "^9.0"

次に、migrateを実行して、認証情報を保持するテーブルを作成します。

> php artisan migrate
Migrating: 2016_06_01_000001_create_oauth_auth_codes_table
Migrated:  2016_06_01_000001_create_oauth_auth_codes_table (0.06 seconds)
Migrating: 2016_06_01_000002_create_oauth_access_tokens_table
Migrated:  2016_06_01_000002_create_oauth_access_tokens_table (0.03 seconds)
Migrating: 2016_06_01_000003_create_oauth_refresh_tokens_table
Migrated:  2016_06_01_000003_create_oauth_refresh_tokens_table (0.03 seconds)
Migrating: 2016_06_01_000004_create_oauth_clients_table
Migrated:  2016_06_01_000004_create_oauth_clients_table (0.01 seconds)
Migrating: 2016_06_01_000005_create_oauth_personal_access_clients_table
Migrated:  2016_06_01_000005_create_oauth_personal_access_clients_table (0.01 seconds)

次に、例えばsample@helog.jpなどのユーザを追加します。
追加する方法はいくつかありますが、今回はお手軽なtinkerコマンドを使います。tinkerコマンドを使うと、コントローラ内のプログラムなどをコマンドラインから対話形式で実行できます。

> php artisan tinker
>>> App\User::create(['name' => 'sample', 'email' => 'sample@helog.jp', 'password' => bcrypt('xxxxxxxx')]);
=> App\User {
     name: "sample",
     email: "sample@helog.jp",
     updated_at: "2019-04-14 16:07:43",
     created_at: "2019-04-14 16:07:43",
     id: 1,
   }

次に、passport:clientコマンドを実行して、アクセストークンを取得するためにのIDとクライアントシークレットキーを取得します。
ここで生成されたクライアントIDとクライアントシークレットキーはメモしておきます。

> php artisan passport:client --install

「app/User.php」を開き、「use Laravel\Passport\HasApiTokens;」を追記、また「use Notifiable;」の部分に「HasApiTokens」を追記します。

...
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
...

「app/Providers/AuthServiceProvider.php」を開き、「use Laravel\Passport\Passport;」と「Passport::routes();」を追記します。

...
use Laravel\Passport\Passport;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
...
    public function boot()
    {
        Schema::defaultStringLength();

        Passport::routes();
    }
}

「config/auth.php」を開き、guards⇒api⇒driverの値をpassportにします。

...
    'guards' => [
        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
...

これで一通り準備は完了です。

APIに認証をかける

それでは、実際にAPIに認証をかけてみます。
例えばユーザ情報を取得するAPI「http://helog.jp/api/user」へのアクセスに認証をかけます。

「routes/api.php」を開き、対象のAPIに「->middleware(‘auth:api’)」を付加します。

Route::get('user', 'UserController@index')->middleware('auth:api');

例1:気軽にAPIにアクセス

昨今、SPAなどで自身のWebアプリケーションのAPIにアクセスする機会が多いと思いますが、Passportではよりスムーズにアクセスできるしくみが用意されています。

まず、必要な設定として「app/Http/Kernel.php」を開き、webミドルウェアに以下を追加します。

...
'web' => [
...
	\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

準備は以上です。
これで、毎回リクエストの度にアクセストークンを送る認証処理を省略することができます。
例えば、認証済みユーザがJavaScriptでAPIにアクセスする場合、アクセストークンを意識する事なく、以下のようにしてaxiosでアクセスできます。

axios.get('/api/user')
	.then(response => {
		console.log(response.data);
	});

例2:jQueryでAPIにアクセス

次に、用意したAPIに対して、外部のWebアプリケーションなどからjQueryでアクセスしてみます。

var $jsondata = {
	grant_type: "password",
	client_id: "1",
	client_secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
	username: "sample@helog.jp",
	password: "xxxxxxxx",
	scope: "*"
};

$.ajax({
	url: '/oauth/token',
	type: 'POST',
	contentType: 'application/json',
	dataType: "json",
	data: JSON.stringify($jsondata)
}).done( ($data) => {
	$access_token = $data.access_token;
});

「client_id」と「client_secret」には先ほど発行したIDとキーを設定します。既存のユーザ名とパスワードを入力して「/oauth/token」にリクエストすると、アクセストークンが取得できます。

取得したアクセストークンを使って、先ほど認証をかけたAPIにアクセスしてみると、無事にユーザ情報データが取得できます。

$.ajax({
	headers: {
		Accept: "application/json",
		Authorization: 'Bearer '+$access_token
	},
	url:'/api/user',
	type:'GET',
})
.done( ($data) => {
	console.log($data);
});

ちなみに認証に失敗、またはトークンに不備があると、認証エラーとなりAPIにはアクセスできません。

Unauthenticated.

少し複雑ですが、慣れてしまえば簡単に構築できますね。
OAuthについても少し詳しくなれたかな。

B!

Comment

コメントはありません

コメントする

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

Monthly Archives