これ、「Laravel5.2でソーシャル連携ウェブサービスの土台を作る。 」のLaravel5.3バージョンです。
5.3ではroutingの設定がフォルダとmiddleware別のファイルに別れたりしました。
laravel/socialiteも前は生のまんま使ったのですが、今回は、socialiteproviders/twitterという、socialite用のプロバイダのライブラリを使いました。
5.2ではAuthControllerとしてログインや会員周りが一つのコントローラーになっていましたが、5.3では4つのControllerに分割されています。(ForgotPasswordController.php、LoginController.php、RegisterController.php、ResetPasswordController.php)
ちょいちょい変わってそうなので、ひととおり実装しました。
プロジェクトの初期化
- 最新のLaravelを落とすと5.3になります。(2017/8/23現在5.4が最新です)
composer create-project --prefer-dist laravel/laravel アプリ名
Homesteadで仮想環境作る
- laravel用の仮想環境のライブラリをrequireする
cd アプリ名
composer require laravel/homestead --dev
- 仮想環境用の設定を自動作成
php vendor/bin/homestead make
- IPとhost名の設定、Hostsの設定
プロジェクト直下にHomestead.yamlってファイルができるので、IPの設定を見る。
ip: "192.168.10.10"
memory: 2048
cpus: 1
hostname: アプリのドメイン名
name: アプリ名
hostnameをアプリのドメイン名を好きな名前に変えて、/etc/hostsに レコードをたす。
192.168.10.10 アプリのドメイン名
- 仮想環境起動
vagrant up
これで待っているとboxのDownloadと仮想マシンの初期化がされます。
Laravelのhomesteadは、ここにホスティングされてます。(一応)
https://atlas.hashicorp.com/laravel/boxes/homestead
- なんかvagrant sshができなかったので、いろいろ調べてたら、Ubuntuの問題っぽかった。これ↓したらなおった。
config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
end
参考:Vagrant で bento/ubuntu-16.04 を vagrant up すると Connection timeout になってしまう
ログイン機能を作る
- 最初に.envにアプリのURLを書いておく
APP_URL=https://アプリのドメイン名
- ユーザー名などで絵文字とか入る可能性があるので、dbのcharsetを
utf8mb4
に変えておく。
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
- vagrantに入る
vagrant ssh
- アプリのディレクトリにcdして、Laravelに最初から用意されている認証用のmigrationとルーティングの設定を実行する
cd アプリ名
php artisan make:auth
php artisan migrate
出来上がったものを確認して見る
実行するとルーティングができてるので、みて見ると、Controllerとか出来上がってる。
php artisan route:list
Domain | Method | URI | Name | Action | Middleware |
---|---|---|---|---|---|
GET/HEAD | / | Closure | web | ||
GET/HEAD | api/user | Closure | api,auth:api | ||
GET/HEAD | home | App\Http\Controllers\HomeController@index | web,auth | ||
GET/HEAD | login | login | App\Http\Controllers\Auth\LoginController@showLoginForm | web,guest | |
POST | login | App\Http\Controllers\Auth\LoginController@login | web,guest | ||
POST | logout | logout | App\Http\Controllers\Auth\LoginController@logout | web | |
POST | password/email | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail | web,guest | ||
GET/HEAD | password/reset | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest | ||
POST | password/reset | App\Http\Controllers\Auth\ResetPasswordController@reset | web,guest | ||
GET/HEAD | password/reset/{token} | App\Http\Controllers\Auth\ResetPasswordController@showResetForm | web,guest | ||
GET/HEAD | register | register | App\Http\Controllers\Auth\RegisterController@showRegistrationForm | web,guest | |
POST | register | App\Http\Controllers\Auth\RegisterController@register | web,guest |
ざっと動いてるか動作確認
この状態で、アクセスhttp://アプリ名/
して見ると、ログインリンクとかついてる。作りやすいな〜。もうソーシャル連携とかいいのでは〜って気分になってくる。
トップページ
会員登録画面
ログイン画面
パスワードリセット
ソーシャル連携を作る
laravelの公式ライブラリのSocialiteでソーシャル連携を作る
https://github.com/laravel/socialite
Twitter経由のログインとユーザー登録
ユーザー登録はメアドで登録ってのも全然ありだが、最初はtwitter経由で登録してあとからTwitter連携外すとか、よくやると思うので、そのようにする。
このサイトの言うこと聞いとけば大体できそう。
Using Twitter Authentication For Login in Laravel 5
socialiteのインストール
composer require laravel/socialite
ライブラリの読み込み
'providers' => [
// Other service providers...
Laravel\Socialite\SocialiteServiceProvider::class,
],
'aliases' => [
snip...
// Other service providers...
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
],
twitter用のproviderインストール
composer require socialiteproviders/twitter
ライブラリの読み込み
'providers' => [
// Other service providers...
Laravel\Socialite\SocialiteServiceProvider::class,
\SocialiteProviders\Manager\ServiceProvider::class, // ←これ追加
],
イベントリスナーにとうろく
protected $listen = [
// 'App\Events\SomeEvent' => [
// 'App\Listeners\EventListener',
// ],
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
// add your listeners (aka providers) here
'SocialiteProviders\Twitter\TwitterExtendSocialite@handle',
],
];
最初から書いてある'App\Events\SomeEvent'...
のところは、よくわからないけどコメントアウトした。
oauth APIのキーを.envに書く。
oauth APIのキーとかはここからとる。
https://apps.twitter.com/
TWITTER_CLIENT_ID=XXXXXXX
TWITTER_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXX
configのservice.phpに設定を追加
'twitter' => [
'client_id' => env('TWITTER_CLIENT_ID'),
'client_secret' => env('TWITTER_CLIENT_SECRET'),
'redirect' => env('URL') . '/twitter/login'
],
twitterのSocialiteFactoryが動くようにする。
AppServiceProvider.phpに起動function作成
private function bootTwitterSocialite()
{
$twitter = $this->app->make('Laravel\Socialite\Contracts\Factory');
$twitter->extend(
'spotify',
function ($app) use ($twitter) {
$config = $app['config']['services.twitter'];
return $twitter->buildProvider(TwitterProvider::class, $config);
}
);
}
twitter用のControllerを作る。
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Laravel\Socialite\Facades\Socialite;
class TwitterAuthController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
public function redirectToProvider()
{
return Socialite::with('twitter')->redirect();
}
public function handleProviderCallback()
{
$user = Socialite::with('twitter')->user();
// $user->token;
// 初めて来た人はユーザー登録、すでにIDがあるひとは、とってくる
$authUser = $this->findOrCreateUser($user);
// その後ログイン
Auth::login($authUser, true);
return redirect('home');
}
/**
* Return user if exists; create and return if doesn't
*
* @param $twitterUser
* @return User
*/
private function findOrCreateUser($twitterUser)
{
$authUser = User::where('twitter_id', $twitterUser->id)->first();
if ($authUser){
return $authUser;
}
// ここは後で書き直します。
}
}
ツイッター経由のloginとcallbackのルーティング追加
Route::get('twitter/login', 'Auth\TwitterAuthController@redirectToProvider');
Route::get('twitter/callback', 'Auth\TwitterAuthController@handleProviderCallback');
ツイッターのアカウント情報を保存するテーブルを作る
ログイン後にaccess_tokenとsecret、ユーザーIDなどを入れるテーブルを作る。
php artisan make:migration create_twitter_users_table
マイグレーションファイルの編集
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTwitterUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('twitter_users', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id');
$table->bigInteger('twitter_user_id');
$table->string('email')->nullable();
$table->string('name');
$table->string('nickname');
$table->string('avatar',1024);
$table->string('token',1024);
$table->string('token_secret',1024);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('twitter_users');
}
}
カラム名がこの感じになってるのは、socialiteprovidersのなかみるとわかるけど、
vendor/socialiteproviders/twitter/src/Server.php
いろんなプロバイダでフィールドが違うのを共通化してる。
もしかして、provider_accounts ってTableつくればよかっただけかも、、。provider_nameとか入れて。
php artisan migrate
modelにrelationを入れておく
public function twitter_users()
{
return $this->hasMany('App\TwitterUser');
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class TwitterUser extends Model
{
/**
* Get the user that owns the twitter user.
*/
public function user()
{
return $this->belongsTo('App\User');
}
}
保存するフィールドのmassassignmentを設定しておく。
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['twitter_user_id','email','name',
'nickname','avatar','token','token_secret',];
準備完了なので、ControllerのfindOrCreateUserを書き直します。
こんな感じ。
/**
* Return user if exists; create and return if doesn't
*
* @param $twitterUser
* @return User
*/
private function findOrCreateUser($twitterUser)
{
$twitterUser = TwitterUser::where('twitter_user_id', $twitter_account->id)->first();
if($twitterUser) {
$authUser = $twitterUser->user;
if ($authUser){
return $authUser;
}
throw new \Exception("twitter userがいるけどuserテーブルに紐づいていない");
}
$user = User::create([
'name' => $twitter_account->name,
'email' => str_random(16)."@example.com", //仮で入れる
'password' => bcrypt(str_random(16)), //仮で入れる
]);
$twitter_user = new TwitterUser([
'twitter_user_id' => $twitter_account->id,
'email' => $twitter_account->email,
'name' => $twitter_account->name,
'nickname' => $twitter_account->nickname,
'avatar' => $twitter_account->avatar,
'token' => $twitter_account->token,
'token_secret' => $twitter_account->tokenSecret,
]);
$user->twitter_users()->save($twitter_user);
return $user;
}
}
これで、https://あぷりのURL/twitter/login
にアクセスすると、新規ユーザーを作成し、ログインまたは既存ユーザーでtwitteridがあったら普通にログイン。
ができるようになります。
twitter経由のログインの場合、メールアドレスとパスワードを仮で設定してあるので、メアドからログインできないようになっていますので適宜ユーザビリティ〜あげちゃってください。
ソースコードはgithubにアップしました。
https://github.com/maimai-swap/laravel5.3-twitter-oauth
ダウンロードしてそのまま使えると思います。