LaravelでSNS認証の後に、自動ログイン出来なかった問題を解決。※Guard利用者

LaravelでSNS認証の後に、自動ログイン出来なかった問題がありました。
事象としては、
・Laravelで Socialite を利用して、Twitter認証を作成
・初認証時は、登録→自動ログインの流れ
・データベースには、ユーザー情報は登録されているが、ログイン出来ず。

問題は、Guardを反映することが出来ていなかったことです。

サイトの作りとして、ログイン時に Auth::guard(‘company’)の認証を持つ作りになっていました。

今回の自動ログインでは、Auth:;login()を使っていました。

Auth::login($myinfo);
//$myinfoはユーザー情報

しかし、これでは、自動ログインすることが出来なかったのです。
認証を与えてあげていなかったのが原因です。
認証を与えて → ログインをさせてあげればよいです。
下記書き方で、自動ログインすることが出来ました。

Auth::guard('company')->login($myinfo);

この辺の記述は、 readouble にも記述されていましたので、参考にしてみてください。

https://readouble.com/laravel/5.7/ja/authentication.html

Twitter APIで、TwitterのEmailを取得。getEmail()が機能しなかった忘備録

LaravelでTwitterログイン機能を設定しようとしています。
LaravelでのSNS認証は、ライブラリの Socialite を使うのがオススメです。

今回は、Laravelでのコード内容ではなくて、Twitterに登録しているemailアドレスを取得するためのTwitter Developer上での設定方法を紹介します。

なぜ、この記事を書こうかと思ったかというと
下記のようにemailをTwitterアカウントから取得しようとしたのですが、$emailがnullで取得できなかったためです。

$user = Socialite::with("twitter")->user(); 
$email =  $user->getEmail();

問題は、Twitter Developer上の設定でした。

Authentication settingsで
Request email address from users is enabled に変更します。

こちらの設定をすることで、

$user = Socialite::with("twitter")->user(); 
$email = $user->getEmail();

$emailが取得することが出来ました。

Twitter API でCallback URLsを設定する方法

TwitterでAPI連携する場合には、Twitter Developerに登録する必要があります。そこで、API keyやアクセストークンなどを取得して、各自のアプリケーションにて設定します。

Keyとは別に、callback urlsを必要するもまります。
Callback URLsがどのように使われるのかについては、Oauth 2.0の仕組を解説している方がいらっしゃったので、割愛します。

OAuth 2.0 の認可レスポンスとリダイレクトに関する説明

今回は、 Twitter Developer でCallback URLsを設定する場所を紹介します。

APPを作る際に、もしかしたら設定する箇所があったのかもしれませんが、APP作成後で追加することが可能です。

Developer Portal > Project > App > Appのsetting > Authentication settings

ここから、Editで、Callback URLsを追加することが可能です。

APPを作る際に、もしかしたら設定する箇所があったのかもしれませんが、作成後でもここから追加することが可能です。

Laravelでパスワードを、特定条件の文字列でハッシュ化する方法

Laravelでハッシュ化する際は、
ファザードで Hash::make(password);
を使うことが大半かと思います。

通常の使い方であればこれでいいと思います。
しかし、このhash方法だと、「\」「$」などの記号も含んだ値が返答されます。

そういった文字列は、都合が悪い場合があります。

その際に、一定の条件に従った文字列を返答してくれるハッシュ方法を紹介します。

MD5方式で、16進数・32文字のハッシュ値を生成する
数字とアルファベットも文字列を含んだ値のみを返します。

使い方はいたって簡単です。

md5(password);

することで、レスポンスされます。

まとめて紹介してくれている記事がありましたので、添付します。

【windows編】AWSのEC2へssh接続するコマンドを紹介

AWSにssh接続するコマンドを紹介します。
簡潔に下記がそのコマンドです。

ssh -i 公開鍵のファイル ec2-user@IPアドレス

公開鍵のファイル

公開鍵のファイル:ディレクトリの場所も指定する必要があります。
例えば、 \Users\Desktop\ssh\aws-and-infra-ssh-key.pem
※ \Users\Desktop\ssh まではディレクトリで、それ以降がファイル名です。

IPアドレス

EC2のインスタンスで登録されているIPアドレスです。
(※Elastic IP を関連付けている場合は、Elastic IP)
確認場所は、

EC2 > インスタンス > 使用するインスタンスを選択

そして、下部に存在するタブの中から「説明」を指定すると
「 IPv4 パブリック IP」という項目で、確認できます。

Laravel Routeにnameを設定・使い方

Laravelでrouteを利用して、viewを呼び出す際に、Routeにnameを設定する方法を紹介します。

routes\web.php(Routeを設定しているファイル)で、nameを設定します。

 Route::get('/profile', 'mypageController@profile')->name('profile');

記載方法はRouteの最後に、
->name(route名称)でrouteの名称を設定することが出来ます。

nameを設定するメリットについては、Qiitaで分かりやすく解説している方がいたので、ご確認下さい。
Laravel使うならrouteには名前をつけたほうが良い

もう少し使い方について解説します。
Routeでのname設定は、名称を設定しただけです。
これを実際にnameを呼び出して使う方法を紹介します。

routeを使うときは、view bladeの中から呼び出します。

例えば、href にて、リンク先を/profileに設定したい際には、
先ほど、設定したnameを呼び出すカタチで下記のようにリンクに設定します。

<a class="nav-link" href="{{ route('profile') }}">Profile</a>

で、この例だと、ただ、リンクに飛ばしているだけじゃないか、と思うかもしれません。

ここで実験して欲しいのですが

Route:

 Route::get('/profile', 'mypageController@profile')->name('profile.gogogo');

View:

<a class="nav-link" href="{{ route('profile.gogogo ') }}">Profile</a>

と設定しても、/profileへリンクされるのです。
nameはただRouteを接続してくれているだけです。
Routeに設定してある、/profileへの接続は変わりません。

もう一点、私が少し混乱したことについて追記します。
Route設定で、group設定を使う人も多くいると思います。

例えば、下記のようにRoute設定した場合

Route::name('admin.')->group(function () {
   Route::get('/profile', 'mypageController@profile')->name('profile'); 
});

Viewでname を使って、Routeを呼び出す方法は

<a class="nav-link" href="{{ route(' admin.profile') }}">Profile</a>

group 化のname設定によって、nameがadmin.XXXXと設定する必要が出てきます。

Laravelのデータベースリレーションを活用して、別のModelのデータを取得する

Laravelのリレーションを活用することで、リレーション先の異なるテーブルとのデータ連携が可能になります。
非常に重要な機能ですので、是非試してみてください。

今回はリレーションについて2点お伝えしていきたいと思います。

( 1 ):Model内でのリレーションの設定方法
( 2 ):Eloquent で、リレーションを活用して別テーブルのデータを取得する方法

つまり、設定 → データ取得する 一連の流れをお伝えしたいと思います。

( 1 ):Model内でのLaravelリレーションの設定方法

こちらは下記サイトの「Eloquent:リレーション」を一度確認してみてください。

リレーションの方法は幾つかあります。
一番使う形式は、下記3つかと思います。基礎的な部分でいうとこの辺を抑えておけば問題ないと思います。

  • 1対1
  • 1対多
  • 多対多

イメージしやすい例は

1対1:
User_id と マイナンバー
※user_id もマイナンバーもどちらもユニークになる存在なので他のデータとの組み合わせは起きません。

1対多:
User_id と コメント履歴
※AさんのコメントはAさんにしか紐づきません。ただし、Aさんは複数コメントする場合はあります。

多 対 多 :
User_id と 好きな飲食店
※Aさんは、飲食店1、2,3が好き、Bさんは、飲食店2、3,5が好き。というように、紐づきが両データに紐づく可能性があります。

設定方法は、Model内にリレーションのメソッドを記述します。
詳細は 「Eloquent:リレーション」 こちらに書いてある通りです。
1つ注意して確認してみて欲しいのは、
データリレーションには、主従の関係性があるということです。

( 2 ):Eloquent で、リレーションを活用して別テーブルのデータを取得する方法

リレーションを設定する目的の1つは、データを取得しやすくすることです。
簡単な例で紹介します。


A // リレーション設定
※ChatRoomUser クラスから、UserクラスへID同士を紐づけしております。

 <?php

namespace App\Models\Chat;

use Illuminate\Database\Eloquent\Model;

class ChatRoomUser extends Model
{

    protected $fillable = ['chat_room_id', 'user_id', 'usertype'];    

    public function InterviewUser()
    {
        return $this->belongsTo('App\Models\User' , 'user_id' ,'id');
    }
} 

B // リレーションデータの取得
これを設定したことによって、Eloquent でChatRoomUser クラスを活用して、Userクラスの情報を取得できます。

$messageUser = ChatRoomUser::whereIn('chat_room_id', $chat_room_id)
->where('usertype', 'Interviewer')
->get();

foreach($messageUser as $user){
$email = $user->InterviewUser->email;
}
 
 

リレーションを活用した取得方法は下記です。
Eloquantで取得データ- > リレーション設定のメソッド -> リレーションした先のModelのデータカラム

今回でいうと:
・ Eloquantで取得データ  $messageUser
・ リレーション設定のメソッド  InterviewUser
・ リレーションした先のModelのデータカラム  email※Userクラスのデータカラム

リレーションデータ取得時の注意

1件のデータに対してメソッドを適用することが出来る

$messageUser は、配列の中に複数のデータが含まれている場合があります。
配列に対して、 リレーション設定のメソッド をアクセスすることは出来ません。
データを一つづつに分解して、そのデータに対してリレーションメソッドを適用しましょう。

LaravelのFacad/Validator で、ユニーク化するテーブルを変更する方法

Laravel初心者の気づきをお伝えします。

マルチ認証の登録・ログイン方法を試していました。
主に参考にしていたのは、下記のやり方です。

https://qiita.com/namizatop/items/5d56d96d4c255a0e3a87

1つ不都合なことがありました。
Adminで新規登録時に、emailがユニークになるデータベーステーブルの対象先がuserのテーブルだったのです。つまり、Adminで登録しようとした際に、Adminでユニーク判定されるのではなくて、userでユニーク判定されてしまっていました。

原因が分からず、Facad の Validatorにデータベーステーブルを指定する場所があるのかなと思い
Illuminate\Support\Facades\Validator::class,
を調べてみても、テーブルを指定しているようにも見えません。

他を調べてみたところ、
下記がテーブルを指定している場所でした…

return Validator::make($data, [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

ここの部分

'email' => 'unique:users'

app/Http/Controllers/Admin/Auth/RegisterController.php

のuser → adminに変更してあげれば、ユニーク化する対象のテーブルがadminへ変更なります。

return Validator::make($data, [
            'name'     => ['required', 'string', 'max:255'],
            'email'    => ['required', 'string', 'email', 'max:255', 'unique:admin'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

composer require google/apiclient:^2.0で、エラーが起きたときの対処法

Errorは下記です。

Your requirements could not be resolved to an installable set of packages.
Installation failed, reverting ./composer.json to its original content.

下記のように、バージョンをアスタリスクで設定してあげるとインストールが実行されました。

composer require google/apiclient:^2.*

Laravelにて、マルチ認証を制御している部分を一番簡潔に説明します。

Laravelで、マルチ認証を知っていますか。マルチ認証ということばは知っていなくても、機能は見たことがあると思います。
代表的なのは、管理者とユーザーに分けたり、企業と求職者に分けたり。
ユーザー別に権限を変え、機能やViewで表示する内容を変えるときに用います。

多くのエンジニアの方々が、マルチ認証について解説してくれています。

ただ、初心者エンジニアからすると、分かるような、分からないような。 要するに、何処かが制御しているのか。まずは知りたい。

と、言った課題を感じます。
(最終的には、フレームワークが何の処理をしているのかを総合的に理解する必要はあると思いますが。)

今回は、簡潔に、マルチ認証を制御しているところは何処なのかを解説します。

色々と調べつつ、実験しながら間違った情報ではないのですが、
確証を持てていないので、違ったら申し訳ないです…
ただ、初心者エンジニアの方で、簡潔に知りたい場合は一読の価値はあるのかなと思います。
では、いってみましょう。

1:マルチ認証を制御するために必要なパーツ
2:マルチ認証を制御しているのに変更する部分

1:マルチ認証を制御するために必要なパーツ

・ログイン時に所有する権限

・ 権限に応じて、閲覧可能(閲覧不可)に制御する方法(機能の場合もあるが…)

簡単にいってしまうと、この2つです。

認証とは、ログインした際に付与されるものです。
(おそらく、sessionが所持しているのだと思ってます。違ったらごめんなさい…)

で、このログインのタイミングで、権限を付与して、その権限に応じて、Viewの制御をしてあげればよいのです。

2:マルチ認証を制御しているのに変更する部分

では、それぞれどこで制御しているのかを確認していきましょう。

ログイン時に所有する権限

権限の付与が全てと言っても過言ではありません。
この権限の付与のために操作するべきところは

・LoginさせるためのController(LoginController.phpなど)
・config/auth.php

この2つです。
(この2つを操作する前に整えなけらばいけないことは省きます。簡潔に。)
guardという機能を使って設定していきます。

LoginさせるためのController (LoginController.phpなど) に対して、
下記を追記します。

protected function guard()
{
    return Auth::guard('admin');
     // adminという権限を付与しています。
     // 名称は必要に応じて変更してOK
 }    

また、Authファザードを使うので、下記を忘れずに。

use Illuminate\Support\Facades\Auth;

config/auth.php を操作していきます。

細かい説明は省いてしまいますが、

     'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],

        'user' => [
            'driver' => 'session',
            'provider' => 'users',
        //    'provider' => 'admins',
        ],

        // Admin用の認証を追加
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],            
    ] 

     'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

         // Admin用のmodel連携を追加 
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Models\Admin::class,
        ]        
    ], 

adminという権限を付与するためにadmin部分を追加します。
これがあることによって

・Auth::guard(‘admin’); が使えるようになります。
・また、adminsというDBからユーザー認証するためのログインユーザーを抽出できます。

先ほども言及した通り、認証はログイン時に付与される権限です。
どこのDBからのログインなのかで、認証を切り分ける仕組みがあるのです。

・ 権限に応じて、閲覧可能(閲覧不可)に制御する方法

権限を付与できたら、後はどの権限なのかによって閲覧可能 / 不可を制御してあげればOKです。

やり方は幾つかあると思います。
Routeで制御する方法と、Controllerで制御する方法です。
どちらにしても、Middlewearを使って制御します。

controllerで制御する方法を紹介しておきます。
ルーティングで振り分けるcontrollerのconstructにて宣言します。
この宣言によって、admin 権限を持って、ログインしたユーザーのみ閲覧することができます。

     public function __construct()
    {
        $this->middleware('auth:admin');
    } 

参考にさせて頂いたサイトは下記です。

ttps://qiita.com/namizatop/items/5d56d96d4c255a0e3a87