iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

2

今天繼續使用者登入的部分.

會員登入資料驗證

為了保護資料庫的完整性及安全性,在使用者發出請求時,務必要對所有傳入的資料驗證後再作處理,避免使用者傳入預期以外的資料,像是E-mail欄位傳送的資料為非E-mail格式的資料時,導致資料處理時發生不可預期的狀況,所以也必須要驗證使用者登入時傳送的資料,在這裡一樣用Laravel提供的Validator驗證資料,驗證器在控制器邏輯會像這樣

app/Http/Controllers/UserAuthController.php

<?PHP
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Validator; //驗證器

class UserAuthController extends Controller
{
    //處理登入資料
    public function signInProcess()
    {
        //接收輸入資料
        $input = request()->all();

        //驗證規則
        $rules = [
            //E-mail
            'email' => [
                'required',
                'max:150',
                'email',
            ],
            //密碼
            'password' => [
                'required',
                'min:6',
            ],
        ];

        //驗證資料
        $validator = Validator::make($input, $rules);

        if($validator->fails())
        {
            //資料驗證錯誤
            return redirect('/user/auth/sign-in')
                ->withErrors($validator)
                ->withInput();
        }
    }
}
?>

驗證E-mail的規則與註冊一樣,在驗證密碼時,因為不用輸入確認密碼,所以就不需要驗證密碼是否與確認密碼欄位相同,根據這樣的規則,我們可以在驗證規則設定中設定成這樣

<?PHP

//驗證規則
$rules = [
    //E-mail
    'email' => [
        'required',
        'max:150',
        'email',
    ],
    //密碼
    'password' => [
        'required',
        'min:6',
    ],
];

?>

在設定完驗證規則後,一樣使用Validator::make()去驗證傳入的資料格式是否正確了,用$validator變數去接收驗證結果,並使用$validator->fails()判斷是否有驗證失敗的情況發生,假如有驗證失敗的話,則將重新導向回到登入頁/user/auth/sign-in,並顯示驗證器驗證的錯誤訊息。

驗證結果畫面
https://ithelp.ithome.com.tw/upload/images/20191013/20105694r0KTqYv0qe.png

取得使用者資料

當使用者傳入的資料格式正確無誤後,之後需要去資料庫撈取使用者的資料,當使用者資料撈取出來後,再判斷書入的密碼有沒有錯誤,當密碼無誤時,就能完成登入的動作,當密碼有錯時,則需要告知使用者輸入的密碼有誤,程式碼會長得像這樣

app/Http/Controllers/UserAuthController.php

<?PHP
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use App\Shop\Entity\User; //使用者 Eloquent ORM Model

class UserAuthController extends Controller
{
    //處理登入資料
    public function signInProcess()
    {
        //接收輸入資料
        $input = request()->all();

        //...中間省略...

        //撈取使用者資料
        $User = User::where('email', $input['email'])->firstOrFail();

        //檢查密碼是否正確
        $is_password_correct = Hash::check($input['password'], $User->password);

        if(!$is_password_correct)
        {
            //密碼錯誤回傳錯誤訊息
            $error_message = [
                'msg' => [
                    '密碼驗證錯誤',
                ],
            ];

            return redirect('/user/auth/sign-in')
                ->withErrors($error_message)
                ->withInput();
        }
    }
}
?>

我們透過E-mail撈取使用者的資料,因為E-mail欄位在資料表是唯一鍵(Unique),可以肯定的是,同個E-mail只會有一筆資料,所以我們透過使用者(User) Eloquent ORM Model 在where條件設定撈取email資料,並使用firstOrFail()的方法限制只撈取第一筆資料,當沒有找到該使用者資料時,則會丟出例外錯誤訊息。

$User = User::where('email', $input['email'])->firstOrFail();

結果畫面
https://ithelp.ithome.com.tw/upload/images/20191013/20105694DDha1mglJw.png

列印Eloquent SQL語法

在資料庫的速度調校中,最重要的就是撈取資料庫的語法邏輯,是否有用到我們設定的欄位索引順序,這樣撈取資料的速度跟效率才會快,在使用Eloquent ORM Model撈取資料後,我們會很好奇,Eloquent是用甚麼樣的語法去資料庫撈資料的,而Laravel有提供DB::getQueryLog()方法,可以印出所有存取資料庫目前執行的SQL語法有哪些,但是為了程式存取的效率,Laravel預設沒有將紀錄SQL語法的功能打開,所以在要取得資料庫SQL語法前,必須先使用DB::enableQueryLog(); 啟用紀錄SQL語法的功能,像這樣

app/Http/Controllers/UserAuthController.php

<?PHP
namespace App\Http\Controllers;

use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use App\Shop\Entity\User; //使用者 Eloquent ORM Model

class UserAuthController extends Controller
{
    //處理登入資料
    public function signInProcess()
    {
        //接收輸入資料
        $input = request()->all();

        //...中間省略...

        //啟用紀錄SQL語法
        DB::enableQueryLog();

        //撈取使用者資料
        $User = User::where('email', $input['email'])->firstOrFail();

        //列印出資料庫目前所有執行的SQL語法
        var_dump(DB::getQueryLog());
        exit();
    }
}
?>

要使用Eloquent存取資料庫前,先啟用紀錄SQL的語法,然後取完資料就可以把SQL語法列印出來了,而記得在最上面要使用use DB;去使用資料庫物件後,才能正常使用喔!

在使用User Eloquent透過E-mail撈取使用者資料後,我們列印出來的語法會長得像這樣

array(1) { [0]=> array(3) { ["query"]=> string(47) "select * from `users` where `email` = ? limit 1" ["bindings"]=> array(1) { [0]=> string(24) "henrychang0202@gmail.com" } ["time"]=> float(4.08) } }

語法資料中的query欄位是指這次撈取用的語法,而bindings欄位則是指語法中的參數,會依序綁訂到語法中問號(?)的位置,像是email=?的問號是整個SQL語法的第一個問號,所有bindings中第一個變數資料則會綁訂到這個地方,而綁定的資料Laravel都會協助處理SQL資料隱碼攻擊(SQL Injection)的問題,所以大大的降低資料庫被攻擊的機會。在time欄位指的是這個語法這次存取資料庫耗費的時間(毫秒ms)。

  • p.s.
    SQL資料隱碼攻擊(SQL Injection):指的是在使用者傳入的字串含有SQL特殊關鍵字,當要去資料庫欄位撈取資料時,會使資料庫的資料被惡意存取或竄改,最嚴重可能會導致整個資料庫資料都被刪除。

這樣我們是不是很清楚知道Eloquent幫我們怎麼樣處理資料庫的資料了,且僅需要使用where()指令就可以很快地對資料庫存取做不同的條件設定,而若有多個where條件時,僅需要在後面繼續加入->where()方法就可以再指定其他的撈取條件了,而且Eloquent也幫我們處理了惱人的SQL資料隱碼攻擊(SQL Injection),這樣在撈取資料是不是很快速且安全呢。

//使用多個where條件撈取使用者資料
$User = User::where('email', $input['email'])
       ->where('type', 'A')
       ->firstOrFail();

上一篇
[Day 31] Laravel實作 - 會員登入及登出(一)
下一篇
[Day 33] Laravel實作 - 會員登入及登出(三)
系列文
Laravel從入門到放棄…………原生PHP (疑?48

1 則留言

1
sean666
iT邦新手 5 級 ‧ 2019-10-14 10:57:03

謝謝小魚分享Laravel系列,寫到3X多天是你的Style呢,要向你看齊!

小魚 iT邦大師 1 級‧ 2019-10-14 11:33:33 檢舉

今年應該會發到4x天...

sean666 iT邦新手 5 級‧ 2019-10-14 13:31:17 檢舉

賺翻了!趕快來佔個位/images/emoticon/emoticon43.gif

我要留言

立即登入留言