iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

今天繼續會員登入的部分.

驗證密碼

在正確取得使用者資料後,可以直接透過$User->password取得使用者資料表欄位的密碼,取得的使用者資料是一個使用者物件,所有資料表的欄位都可以透過物件的屬性值取得,所以我們也可以透過$User->nickname取得使用者的暱稱。

在取得使用者的密碼後,可以用Hash::check()檢查使用者的密碼是否正確,第一個參數為使用者目前表單傳入的密碼$input['password'],第二個參數為Hash加密過的密碼,密碼檢查結果會回傳布林值。
Laravel不能直接比較兩次Hash值是否一樣來判斷密碼是否正確,同樣的Key每次Hash完字串還是會不一樣,必須透過Laravel提供的方法來判斷Hash值。

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

當密碼檢查錯誤時,一樣需要回傳錯誤訊息,告知使用者密碼驗證發生錯誤,我們一樣可以使用錯誤訊息模板元件來顯示我們的錯誤訊息,原本的withError()是傳入驗證器變數$validator,我們這邊僅需要傳入錯誤訊息陣列的變數,並將訊息寫到陣列中msg鍵值內即可。

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

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

會員登入

當會員的E-mail及密碼驗證成功後,我們就可以將會員編號記錄在session中,用session中是否有會員編號的資料,來識別會員是否已登入,會員登入紀錄session的程式會長得像這樣

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();

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

        //session紀錄會員編號
        session()->put('user_id', $User->id);

        //重新導向到原先使用者造訪頁面,沒有嘗試造訪頁則重新導向回首頁
        return redirect()->intended('/');
    }
}
?>

直接使用session()方法,記錄使用者編號到session中,之後就可以從session取得會員編號了

session()->put('user_id', $User->id);

使用者在瀏覽網站時,會存取不同的頁面,但當使用者未登入狀況下,瀏覽到需要登入才能存取的使用者交易資料頁 /transactoin (get) 時我們會將使用者重新導向到登入頁 /user/auth/sign-in (get) 進行登入,當使用者登入完成後,若能再將使用者重新導向回到原本使用者想要存取的使用者交易紀錄頁 /transaction (get),讓使用者繼續做後面的動作,這樣的操作體驗是比較好的。

Laravel為了達到這樣的操作體驗,提供redirect()->intended()方法,可以讓使用者重新導向回本來登入前的頁面,但若使用者直接存取登入頁 /user/auth/sign-in (get) 時,沒有原先的操作頁面,在此方法可以加入預設要存取的頁面,目前是設定為首頁redirect()->intended('/'),所以當沒有原先操作頁面時,則重新導向至首頁 / (get)

Session設定

所有session的設定都放在config/session.php檔案中,Laravel原生支援file、cookie、database、apc、memcached、redis及array這些儲存方式,若只有單台主機時,大部分session是儲存在本地端的檔案(file)中,但若同時有多台主機在服務時,session存在本地端無法作同步共用,會造成使用者在主機A登入後,但在主機B則為未登入的狀況。

為了處理這樣的情況,則需要將session放在共用的主機上,像是database、redis或memchached中,這樣當使用者在作登入,紀錄會員編號到session後,才能夠同時在多台主機登入,當有這樣的使用情境時,可以隨時修改session的儲存方式。

config/session.php

<?php

use Illuminate\Support\Str;

return [

    //session儲存方式
    'driver' => env('SESSION_DRIVER', 'file'),

    //session存活時間(分鐘)
    'lifetime' => env('SESSION_LIFETIME', 120),

    //session的cookie名稱
    'cookie' => env(
        'SESSION_COOKIE',
        Str::slug(env('APP_NAME', 'shop_laravel'), '_').'_session'
    ),

];

Session儲存的方式可以在driver鍵值上做設定,隨著環境不同做不同的設定,像是在本地端開發環境只有一台電腦的話,就可以將session儲存方式設定為file,若為正式主機的話,就可以將session儲存方式設定為database、redis或memcached,依照不同的環境去設定。

Session存活時間可以在lifetime鍵值上做設定,看使用者登入的資料需要保留多久,在這個設定時間過後,Session就會過期,將使用者強制登出,可以依照專案的需求去做調整。

Session Cookie名稱可以在cookie鍵值上做設定,設定Session在Cookie的名稱鍵值是什麼,通常是為設定成專案名稱,在這裡就設定為shop_laravel,所以在Cookie就會以這個名稱當作儲存Session Cookie的鍵值。

這些設定如果需要依照環境不同而有不同的設定,就可以將這些設定值一樣設定在.env檔案中。

登入身分畫面檢視

在網站的畫面上,我們會需要依照使用者登入與否,來顯示不同的畫面,像是尚未登入時,則必需要顯示登入及註冊的連結。而登入後則不需要顯示登入及註冊的連結,而是需要顯示登出的連結,依照使用者登入與否的不同情境,需要有不同的畫面模板。

我們在模板中可以使用session()->has()的方法,判斷是否有我們登入時紀錄的user_id鍵值,在識別使用者是否已經登入,這時候我們就會用到Blade模板提供的@if、@else及@endif的功能,來判斷在什麼狀況需要顯示什麼樣的資料

resources/views/layout/master.blade.php

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>@yield('title') - Shop Laravel</title>
        <script src="http://cdn.bootcss.com/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
        <link href=" https://netdna.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css " rel="stylesheet" type="text/css" />
    </head>
    <boby>
        <header>
            <ul class="nav">
                @if(session()->has('user_id'))
                    <li><a href="/user/auth/sign-out">登出</a></li>
                @else
                    <li><a href="/user/auth/sign-in">登入</a></li>
                    <li><a href="/user/auth/sign-up">註冊</a></li>
                @endif
            </ul>
        </header>
        <div class="container">
            @yield('content')
        </div>
        <footer>
            <a href="#">聯絡我們</a>
        </footer>
    </body>
</html>

app/Http/Controllers/HomeController.php

<?PHP
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function indexPage()
    {
        $binding = [
            'title' => '註冊',
        ];
        return view("home", $binding);
    }
}
?>

resources/views/home.blade.php

<!-- 指定繼承 layout.master 母模板 -->
@extends('layout.master')

<!-- 傳送資料到母模板,並指定變數為title -->
@section('title', $title)

<!-- 傳送資料到母模板,並指定變數為content -->
@section('content')
<div class="container">
    <p>一直一直變動的資料</p>
    <p>一直一直變動的資料</p>
    <p>一直一直變動的資料</p>
    <p>一直一直變動的資料</p>            
</div>
@endsection

畫面顯示

會員登出

在讓會員登入後,為了使用者個人資料的安全性,會需要實作登出的功能,避免帳號被別人誤用,在登出的邏輯僅需要使用session()->forget()方法將儲存在Session的user_id鍵值清除即可,只要用於判斷是否有登入的Session user_id鍵值不存在,就表示會員已經登出了。

在清除Session鍵值後,就可以使用redirect()將會員重新導向回網站首頁,讓使用者可以回到首頁做後續的操作就好了。

app/Http/Controllers/UserAhthController.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 signOut()
    {
        //清除Session
        session()->forget('user_id');

        //重新導向回首頁
        return redirect('/');
    }
}
?>

會員登入及登出的總結

在會員登入頁面時,我們一樣沿用了註冊頁的錯誤訊息模板元件,模板元件化可以減少重複的程式,且容易修改異動。在登入後一樣使用驗證器Validator去驗證使用者傳入的資料,確保資料庫資料的安全性及完整性。存取資料庫時使用Eloquent ORM Model可以讓我們快速的產生撈取資料庫的語法,並幫我們處理SQL資料隱碼攻擊(SQL Injection)的資料庫安全性問題,在取得資料後,亦可以使用Hash::check()針對註冊時加密的密碼做比對,比對加密資料時,Laravel一樣會使用環境變數中的APP_KEY當作密鑰進行加密資料的比對,確保資料的安全性。

登入後會員的資料需要儲存在Session中,而Sessoin可以透過設定檔去調整,在不同環境下,要用什麼樣不同的Session儲存方式,亦可隨時去做調整,在有會員登入的狀態時,模板也可以依照不同的身分狀態,去顯示不同的畫面,登出時僅需要用session()->forget()方法,就可以快速的將Session資料做清除了。

原本的資料驗證撈取資料庫資料及安全性密碼驗證及安全性Session資料處理的邏輯及流程,現在只需要幾行的程式就可以完成了,而且在使用Eloquent ORM Model撈取完資料後,也可以將其存取資料庫的語法印出做檢視除錯,在會員登入完成後,接下來我們就可以開始使用會員的身分,進行商品的新增管理了。


上一篇
[Day 32] Laravel實作 - 會員登入及登出(二)
下一篇
[Day 34] Laravel實作 - 商品管理與瀏覽(一)
系列文
Laravel從入門到放棄…………原生PHP (疑?48

尚未有邦友留言

立即登入留言