
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、前回 Laravelのユーザーでwordpressへログインできるようにする では、Laravel
に登録されているユーザー情報を使ってwordpress
へログインする方法を紹介しました。
このような使い方をすることで、例えばLaravel
で開発されたサイトであっても各ユーザーがwordpress
で開設された共同ブログにログインし、ユーザー全員で情報発信することができるようになります。
ただこの場合、ひとつある課題が発生してしまいます。
それは・・・・・・すでにLaravel
のサイトにログインしたのに、再度ブログページでログインを要求される、つまりユーザビリティがあまり良くない状況になってしまうわけです。
そこで!
今回は独自プラグインlaravel-auto-login
を作成して、すでにLaravel
でログインしている場合は自動的にwordpress
にログインができるようにしてみます。
ぜひ参考にしてみてくださいね。
※ 開発環境: Laravel 5.7、wordpress 5.0
目次 [非表示]
自動ログインの手順
おおまかに自動ログインは次の手順で行います。
- Laravelのユーザーデータが自動ログイン用のトークンを保持する
- wordpressでそのトークンを使って認証をする
- 自動ログインを実行する
では、実際に開発していきましょう!
Laravel側の作業
自動ログイン用トークンのためのフィールドを追加する
まずはLaravel
のユーザー情報を保存しているテーブルにauto_login_token
という名前のフィールドを追加します。
今回はすでにあるマイグレーションdatabase/migrations/****_**_**_******_create_users_table.php
を変更します。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('auto_login_token')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
設定が終わったら、マイグレーションを実行しておいてください。
テーブル構造はこのようになります。
自動ログイン・トークンのイベントを作成する
まず、auto_login_token
フィールドは、次のような使い方をします。
- ログインしたら新しい文字列を保存
- ログアウトしたら空にする
そのため、これらを実現するためにログイン&ログアウト時に実行されるイベントを作っていきます。
まずはapp/Providers/EventServiceProvider.php
を開いて、次のようにログインとログアウトに実行されるイベントを登録します。
// app/Providers/EventServiceProvider.php
protected $listen = [
'Illuminate\Auth\Events\Authenticated' => [
'App\Listeners\LogAuthenticated',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
// 省略
];
そして、次のコマンドを実行してイベントリスナーを作成しましょう。
php artisan event:generate
すると、app/Listeners
フォルダの中に以下2つのファイルが作成されていますので、これら2つのファイル内にコードを書き込んでいきます。
- LogAuthenticated.php
- LogSuccessfulLogout.php
※ なお、ログイン&ログアウト時のイベントを詳しく知りたい方は、選べる全4種類!Laravelで最終ログイン&ログアウト日時を保存(たった4行〜イベントまで)をご覧ください。
LogAuthenticated
ログインが成功したときのイベント 認証が成功したときのイベントですので、次のよう新しいauto_login_token
を登録します。
public function handle(Authenticated $event)
{
$user = $event->user;
$user->auto_login_token = $user->id .'-'. str_random(32);
$user->save();
}
これでログインしたら各ユーザーに一意な文字列が保存されることになります。
※ この方法は、ログインしてページ移動すると毎回呼ばれます。もしログイン時に1回だけ実行したい場合はLoginController.php
のauthenticated()
で実装してください。詳しくは選べる全4種類!Laravelで最終ログイン&ログアウト日時を保存をご覧ください。
LogSuccessfulLogout
ログアウトした時に実行するイベントです。
auto_login_token
を初期化します。
public function handle(Logout $event)
{
$user = $event->user;
$user->auto_login_token = null;
$user->save();
}
ログアウトすると、次のように初期化されます。
自動ログインURLを作成する
では、Laravel
側最後の作業として、自動ログインURLを作成します。
なお、簡単にどこからでも自動ログインURLを取得できるようにUserモデルにaccessor
を作ります。
// app/User.php
class User extends Authenticatable
{
// 省略
// Accessor
public function getAutoLoginUrlAttribute() {
return 'http://wordpress.example.com/laravel-auto-login?token='. $this->auto_login_token;
}
}
これで、$user->auto_login_url
とすると次のような「自動ログインURL」が取得できるようになります。
http://wordpress.example.com/laravel-auto-login?token=1-rDvmDmQTrlFDx1NqHgOZkK4fGYRW0vGn
なお、laravel-auto-login
というページは、これからプラグインで作成する自動ログイン専用のページです。
wordpress側の作業
続いてwordpress
側の作業です。
注意点
今回もLaravel側のDBに直接アクセスするコードを書いていきますが、もし前回記事で作った独自プラグインlaravel-authentication
を使っている場合はデータベース接続情報の部分はwp-config.php
へ移動しておいてください。(こうしないと定義が重複しているとしてエラーが発生します)
// wp-config.php
// LaravelのDB情報
define('LARAVEL_DB_TYPE', 'mysql');
define('LARAVEL_DB_HOST', 'localhost');
define('LARAVEL_DB_PORT', '3306');
define('LARAVEL_DB_DATABASE', 'YOUR-LARAVEL-DB-NAME');
define('LARAVEL_DB_USERNAME', 'YOUR-USER-NAME');
define('LARAVEL_DB_PASSWORD', 'YOUR-PASSWORD');
define('LARAVEL_DB_USER_TABLE', 'users'); // 名前が違う場合は変えてください
独自プラグイン開発の準備
wp-content/plugins
フォルダの中にlaravel-auto-login
フォルダを作成し、その中にlaravel-auto-login.php
を作成します。
独自プラグインをつくる
では、今回の記事でメインになる独自プラグインのコードです。
<?php
/*
Plugin Name: Laravel Auto Login
Description: A plugin that allows to auto-login by Laravel users.
Version: 1.0.0
Author: Sukohi Kuhoh
Author URI: https://blog.capilano-fw.com
*/
add_filter('wp', 'laravel_auto_login');
function laravel_auto_login()
{
global $wp;
// 自動ログイン専用ページかどうかをチェック
if($wp->request == 'laravel-auto-login') {
// DB接続
try {
$pdo = new PDO(
LARAVEL_DB_TYPE . ':' .
'host=' . LARAVEL_DB_HOST . ';' .
'port=' . LARAVEL_DB_PORT . ';' .
'dbname=' . LARAVEL_DB_DATABASE . ';' .
'charset=utf8mb4', // DSN
LARAVEL_DB_USERNAME,
LARAVEL_DB_PASSWORD
);
} catch (Exception $e) {
throw new Exception('Failed to connect to database.');
}
$token = trim($_GET['token']);
// トークンを使ってLaravelユーザーを取得
$sql = $pdo->prepare('SELECT id,name,email FROM ' . LARAVEL_DB_USER_TABLE . ' WHERE auto_login_token=:token');
$sql->bindParam(':token', $token);
$sql->execute();
$laravel_user = $sql->fetch();
if ($laravel_user) {
$laravel_name = $laravel_user['name'];
$laravel_email = $laravel_user['email'];
$password = md5(uniqid(rand(), 1));
$user_id = null;
$wp_user = get_user_by('email', $laravel_email);
if (!$wp_user) { // ユーザー登録
$user_id = wp_insert_user([
'user_login' => md5(uniqid(rand(), 1)),
'user_pass' => $password,
'user_email' => $laravel_email,
'display_name' => $laravel_name,
'role' => 'author'
]);
} else { // ユーザー更新
$user_id = $wp_user->ID;
wp_update_user([
'ID' => $user_id,
'user_pass' => $password,
'user_email' => $laravel_email,
'display_name' => $laravel_name
]);
}
// ユーザーIDを使ってログイン
wp_set_current_user($user_id);
wp_set_auth_cookie($user_id);
// ダッシュボードへリダイレクト
wp_redirect('wp-admin/');
exit();
}
// ここまででログインできなかったら失敗。Laravelへリダイレクト
wp_redirect('http://laravel.example.com/login'); // ご自身のURLへ変更してください
exit();
}
}
【追記:2019.01.26】コードに間違いがありましたので変更しました。
では内容をひとつずつ説明していきます。
自動ログイン専用ページかどうかをチェック
まず、このプラグインは全ページで呼び出されることになります。
そして、自動ログイン専用ページのURL(つまり、http://******/laravel-auto-login
)にアクセスがあった場合だけコードを実行することになります。
DB接続
データベースの接続は前回のlaravel-authentication
と同じくPDO
です。
ただし、違っているのはDB接続に失敗した場合は例外処理を実行するようにしています。
トークンを使ってLaravelユーザーを取得
続いて、パラメータに含まれているトークンからLaravel
側のユーザーデータを取得します。
ユーザー登録&ユーザー更新
もしLaravel
のユーザーが見つかった場合、wordpress
に同じユーザーが存在しているかをチェックし、なければ新規登録。あればそのユーザーデータを更新するようにします。
なお、ここの処理はほとんど前回記事と同じですが、それぞれユーザーIDを取得している部分が違います。これは後でユーザーをログインさせるために必要になるからです。
また、パスワード情報は取得できないのでランダムな文字列を使っています。
ユーザーIDを使ってログイン
wordpress
側にユーザーが準備できたら、そのユーザーIDを使ってログインさせます。
ダッシュボードへリダイレクト
wordpress
にログインさせたら、ダッシュボードへリダイレクトします。
※ なお、もし自動ログインに失敗したらLaravel
のログインページへ移動するようにしています。
プラグインを有効化する
では、準備は整いましたのでプラグインを有効化しましょう。
プラグインページで次のリンクをクリックします。
テストしてみる
では、準備はすべて整ったのでテストしてみましょう。
まず、Laravel
のresources/views/home.blade.php
内に自動ログインのリンクを作成してログインします。
<a href="{{ auth()->user()->auto_login_url }}">自動ログイン</a>
するとこのようにリンクが表示されます。
クリックしてみます。
うまく自動ログインできました!
今回は以上になります。
お疲れ様でした。
おまけ – 1(セキュリティを向上させる)
ちなみに追加するかどうか迷った結果、できるだけ根本的な部分を紹介するために省いた機能をおまけとして紹介します。
今回紹介した内容だと、アクセストークンはログインしたときにだけ更新されることになります。そのため、可能性としてはその後長い間トークンが同じままになる場合もあるわけです。これはセキュリティ上あまりいいとは言えません。
【追記: 2019.01.26】 LogAuthenticated
を使って実装している場合、ログイン中にページ移動があれば毎回自動ログインのトークンは更新されます。内容が正確ではなく申し訳ございません。そのため、以下の内容はもしLoginController.php
で実装していた場合に追加する内容としてお読みください。
そのため、自動ログイン・トークンが使えるのは一回だけにし、さらにログインしていればページ移動する度にトークンを更新するようにしてみます。
ページを移動する度にトークンを更新する
まず、Laravel
側です。
ページにアクセスする度にログインをチェックするためにUpdateAutoLoginToken
という名前のミドルウェアを作りましょう。
php artisan make:middleware UpdateAutoLoginToken
中身はこうなります。(太字が追加した部分です)
public function handle($request, Closure $next)
{
if(auth()->check()) {
$user = $request->user();
$user->auto_login_token = $user->id .'-'. str_random(32);
$user->save();
}
return $next($request);
}
そして、このミドルウェアをapp/Http/Kernel.php
に登録します。
protected $middlewareGroups = [
'web' => [
// 省略
\App\Http\Middleware\UpdateAutoLoginToken::class
],
// 省略
];
これで、ログイン状態であればページ移動したときに必ず自動ログイン・トークンを更新するようになります。
自動ログインしたらトークンを削除する
次にwordpress
側です。
自動ログインが成功した時点でトークンを削除します。
// ユーザーIDを使ってログイン
// 省略
// Laravel側の自動ログイントークンを初期化
$sql = $pdo->prepare('UPDATE '. LARAVEL_DB_USER_TABLE .' SET auto_login_token = :token');
$sql->bindValue(':token', null, PDO::PARAM_NULL);
$sql->execute();
// ダッシュボードへリダイレクト
// 省略
これでよりセキュアなサイト構成になりました。
おまけ – 2(トークン更新を一元管理する)
今回は説明のために各場所でトークンを更新するようにしていましたが、複数回呼ばれるコードは一元管理すべきです。そのため、次のような次のようなメソッドを用意するといいでしょう。
// User.php
public function updateAutoLoginToken() {
$this->auto_login_token = $this->id .'-'. str_random(32);
$this->save();
}
使い方はこうなります。
$user->updateAutoLoginToken();
おわりに
ということで、前回に引き続きLaravel
とwordpress
を統合する話題をお届けしました。
ちなみに、今回の独自プラグインは前回のlaravel-authentication
と併用できるので、wordpress
のログインページからLaravel
のユーザー情報でログインすることもできます。
なお、記事中でも言いましたが、define()
部分が重複してしまうとPHPエラー(実際にはNotice)が発生してしまうので、wp-config.php
へ移動させました。
もちろん我々プログラマーだけが使う分にはこの形でもいいのでしょうが、通常のユーザーが使う場合にはファイルを開いて編集というのは少し怖かったりもします。
そのため、もし気になるようでしたらwordpress
の設定ページでDBへの接続情報を編集できるようにするといいでしょう。(気が向いたらこの部分も記事にしてみたいと思いますね)
ではでは〜!