@shin1x1
2015/04/20 21th Kansai PHP Study
認証機能に学ぶ
Laravel 5 アプリケーション
デフォルト認証機能
Authentication
(c) 2015 Masashi Shinbara @shin1x1
• デフォルトプロジェクトに含まれている
• php artisan migrateすれば、すぐに使える
• 実際に見てみよう
ユーザ登録
(c) 2015 Masashi Shinbara @shin1x1
ログイン
(c) 2015 Masashi Shinbara @shin1x1
パスワードリセット
(c) 2015 Masashi Shinbara @shin1x1
こんな機能も
(c) 2015 Masashi Shinbara @shin1x1
• Cookieトークンによる自動ログイン

(Remeber me)
• Basic認証(要実装)
• ソーシャル認証(要実装 / Twitter等)
認証機能に見る
アプリケーション実装例
Flow
(c) 2015 Masashi Shinbara @shin1x1
Routing
(c) 2015 Masashi Shinbara @shin1x1
Routing
Route::controllers([

'auth' => 'AuthAuthController',

'password' => 'AuthPasswordController',

]);
/auth, /password へのルーティング
コントローラのメソッドへ連結
Controller Method
(c) 2015 Masashi Shinbara @shin1x1
• HTTPメソッド + パス
• GET /auth/register

=> getRegister()
• POST /auth/register

=> postRegister()
Routing - auth
(c) 2015 Masashi Shinbara @shin1x1
Method URI Action
GET¦HEAD /auth/register AuthController@getRegister
POST /auth/register AuthController@postRegister
GET¦HEAD /auth/login AuthController@getLogin
POST /auth/login AuthController@postLogin
GET¦HEAD /auth/logout AuthController@getLogout
Routing - password
(c) 2015 Masashi Shinbara @shin1x1
Method URI Action
GET¦HEAD /password/email PasswordController@getEmail
POST /password/email PasswordController@postEmail
GET¦HEAD /password/reset PasswordController@getReset
POST /password/reset PasswordController@postReset
Controller
(c) 2015 Masashi Shinbara @shin1x1
Controller
(c) 2015 Masashi Shinbara @shin1x1
• AuthControllerとPasswordController
• コンストラクタのみで、実処理はトレイトに実装
• 独自コントローラにもトレイトを再利用できる
Controller
<?php namespace AppHttpControllersAuth;



// (snip)



class AuthController extends Controller

{

use AuthenticatesAndRegistersUsers;



public function __construct(Guard $auth, Registrar $registrar)

{

$this->auth = $auth;

$this->registrar = $registrar;



$this->middleware('guest', ['except' => 'getLogout']);

}



}
コンストラクタインジェクション
Controller
<?php namespace AppHttpControllersAuth;



// (snip)



class AuthController extends Controller

{

use AuthenticatesAndRegistersUsers;



public function __construct(Guard $auth, Registrar $registrar)

{

$this->auth = $auth;

$this->registrar = $registrar;



$this->middleware('guest', ['except' => 'getLogout']);

}



}
ミドルウェア(ログイン済みなら、リダイレクト)
Controller
<?php namespace AppHttpControllersAuth;



// (snip)



class AuthController extends Controller

{

use AuthenticatesAndRegistersUsers;



public function __construct(Guard $auth, Registrar $registrar)

{

$this->auth = $auth;

$this->registrar = $registrar;



$this->middleware('guest', ['except' => 'getLogout']);

}



}
トレイト
Constructor Injection
(c) 2015 Masashi Shinbara @shin1x1
• コンストラクタでタイプヒンティングで指定
• IoC コンテナから、インスタンスを注入
• インスタンスが無ければ、フレームワークが生成
Constructor Injection
public function __construct(Guard $auth, Registrar $registrar)

{

$this->auth = $auth;

$this->registrar = $registrar;



$this->middleware('guest', ['except' => 'getLogout']);

}
$auth = Guard クラスのインスタンス
$registar = Registarクラスのインスタンス
Middleware
(c) 2015 Masashi Shinbara @shin1x1
• Decoratorパターン
• 適用ミドルウェアをAppHttpKernelで定義
• ミドルウェアは、次のミドルウェアを呼ぶ
• 一つの処理を行うミドルウェアを重ねていく
Middleware
public function handle($request, Closure $next)

{

if ($this->auth->check()) {

return new RedirectResponse(url('/home'));

}



return $next($request);

}
ログイン済みなら、/homeへリダイレクト
そうで無ければ、次のミドルウェアを呼ぶ
Middleware Chain
CheckForMaintenanceMode
EncryptCookies
AddQueuedCookiesToResponse
StartSession
ShareErrorsForSession
RedirectIfAuthenticate
Controller method
ミドルウェアチェイン
メンテナンスモード切り替え
クッキーの複合、暗号
クッキーをレスポンスヘッダにセット
セッション開始、後処理
エラー情報をビューにセット
ログイン済みならリダイレクト
Controller method
Trait
(c) 2015 Masashi Shinbara @shin1x1
• AuthControllerとPasswordController
• コンストラクタのみで、実処理はトレイトに実装
• 独自コントローラにもトレイトを再利用できる
Trait
public function getRegister()

{

return view('auth.register');

}



public function postRegister(Request $request)

{

$validator = $this->registrar->validator($request->all());



if ($validator->fails())

{

$this->throwValidationException(

$request, $validator

);

}



$this->auth->login($this->registrar->create($request->all()));



return redirect($this->redirectPath());

}
method
Trait
public function getRegister()

{

return view('auth.register');

}



public function postRegister(Request $request)

{

$validator = $this->registrar->validator($request->all());



if ($validator->fails())

{

$this->throwValidationException(

$request, $validator

);

}



$this->auth->login($this->registrar->create($request->all()));



return redirect($this->redirectPath());

}
method injection
Service
(c) 2015 Masashi Shinbara @shin1x1
Service
(c) 2015 Masashi Shinbara @shin1x1
• コントローラから起動

(コントローラ以外からの呼び出しも可)
• ビジネスロジックを実装
• 永続化などは、Eloquent(モデル)に移譲
• GuardクラスとRegistrarクラス
Service - Registrar
class Registrar implements RegistrarContract

{

public function validator(array $data)

{

return Validator::make($data, [

'name' => 'required|max:255',

'email' => 'required|email|max:255|unique:users',

'password' => 'required|confirmed|min:6',

]);

}



public function create(array $data)

{

return User::create([

'name' => $data['name'],

'email' => $data['email'],

'password' => bcrypt($data['password']),

]);

}

}
validator builder
Service - Registrar
class Registrar implements RegistrarContract

{

public function validator(array $data)

{

return Validator::make($data, [

'name' => 'required|max:255',

'email' => 'required|email|max:255|unique:users',

'password' => 'required|confirmed|min:6',

]);

}



public function create(array $data)

{

return User::create([

'name' => $data['name'],

'email' => $data['email'],

'password' => bcrypt($data['password']),

]);

}

}
business logic
Controller(with Trait)
public function postRegister(Request $request)

{

$validator = $this->registrar->validator($request->all());



if ($validator->fails())

{

$this->throwValidationException(

$request, $validator

);

}



$this->auth->login($this->registrar->create($request->all()));



return redirect($this->redirectPath());

}
call service
call servicecall service
Model(Eloquent)
(c) 2015 Masashi Shinbara @shin1x1
Model(Eloquent)
(c) 2015 Masashi Shinbara @shin1x1
• Contracts(インターフェース)を実装
• プロパティ定義のみ
• 実処理は、トレイトに実装
Model(Eloquent)
class User extends Model implements AuthenticatableContract,
CanResetPasswordContract

{

use Authenticatable, CanResetPassword;

protected $table = 'users';

protected $fillable = ['name', 'email', 'password'];

protected $hidden = ['password', 'remember_token'];

}
Contract(interface)
Trait
まとめ
まとめ
(c) 2015 Masashi Shinbara @shin1x1
• 認証実装は、良いサンプル実装
• 役割を分け、シンプルな実装を
• こうしないといけないわけじゃない
• Laravelの実装で、アーキテクチャを学ぶ
@shin1x1
(c) 2015 Masashi Shinbara @shin1x1

認証機能で学ぶ Laravel 5 アプリケーション

  • 1.
     @shin1x1 2015/04/20 21th KansaiPHP Study 認証機能に学ぶ Laravel 5 アプリケーション
  • 2.
  • 3.
    Authentication (c) 2015 MasashiShinbara @shin1x1 • デフォルトプロジェクトに含まれている • php artisan migrateすれば、すぐに使える • 実際に見てみよう
  • 4.
  • 5.
  • 6.
  • 7.
    こんな機能も (c) 2015 MasashiShinbara @shin1x1 • Cookieトークンによる自動ログイン
 (Remeber me) • Basic認証(要実装) • ソーシャル認証(要実装 / Twitter等)
  • 8.
  • 9.
    Flow (c) 2015 MasashiShinbara @shin1x1
  • 10.
    Routing (c) 2015 MasashiShinbara @shin1x1
  • 11.
    Routing Route::controllers([
 'auth' => 'AuthAuthController',
 'password'=> 'AuthPasswordController',
 ]); /auth, /password へのルーティング コントローラのメソッドへ連結
  • 12.
    Controller Method (c) 2015Masashi Shinbara @shin1x1 • HTTPメソッド + パス • GET /auth/register
 => getRegister() • POST /auth/register
 => postRegister()
  • 13.
    Routing - auth (c)2015 Masashi Shinbara @shin1x1 Method URI Action GET¦HEAD /auth/register AuthController@getRegister POST /auth/register AuthController@postRegister GET¦HEAD /auth/login AuthController@getLogin POST /auth/login AuthController@postLogin GET¦HEAD /auth/logout AuthController@getLogout
  • 14.
    Routing - password (c)2015 Masashi Shinbara @shin1x1 Method URI Action GET¦HEAD /password/email PasswordController@getEmail POST /password/email PasswordController@postEmail GET¦HEAD /password/reset PasswordController@getReset POST /password/reset PasswordController@postReset
  • 15.
    Controller (c) 2015 MasashiShinbara @shin1x1
  • 16.
    Controller (c) 2015 MasashiShinbara @shin1x1 • AuthControllerとPasswordController • コンストラクタのみで、実処理はトレイトに実装 • 独自コントローラにもトレイトを再利用できる
  • 17.
    Controller <?php namespace AppHttpControllersAuth;
 
 //(snip)
 
 class AuthController extends Controller
 {
 use AuthenticatesAndRegistersUsers;
 
 public function __construct(Guard $auth, Registrar $registrar)
 {
 $this->auth = $auth;
 $this->registrar = $registrar;
 
 $this->middleware('guest', ['except' => 'getLogout']);
 }
 
 } コンストラクタインジェクション
  • 18.
    Controller <?php namespace AppHttpControllersAuth;
 
 //(snip)
 
 class AuthController extends Controller
 {
 use AuthenticatesAndRegistersUsers;
 
 public function __construct(Guard $auth, Registrar $registrar)
 {
 $this->auth = $auth;
 $this->registrar = $registrar;
 
 $this->middleware('guest', ['except' => 'getLogout']);
 }
 
 } ミドルウェア(ログイン済みなら、リダイレクト)
  • 19.
    Controller <?php namespace AppHttpControllersAuth;
 
 //(snip)
 
 class AuthController extends Controller
 {
 use AuthenticatesAndRegistersUsers;
 
 public function __construct(Guard $auth, Registrar $registrar)
 {
 $this->auth = $auth;
 $this->registrar = $registrar;
 
 $this->middleware('guest', ['except' => 'getLogout']);
 }
 
 } トレイト
  • 20.
    Constructor Injection (c) 2015Masashi Shinbara @shin1x1 • コンストラクタでタイプヒンティングで指定 • IoC コンテナから、インスタンスを注入 • インスタンスが無ければ、フレームワークが生成
  • 21.
    Constructor Injection public function__construct(Guard $auth, Registrar $registrar)
 {
 $this->auth = $auth;
 $this->registrar = $registrar;
 
 $this->middleware('guest', ['except' => 'getLogout']);
 } $auth = Guard クラスのインスタンス $registar = Registarクラスのインスタンス
  • 22.
    Middleware (c) 2015 MasashiShinbara @shin1x1 • Decoratorパターン • 適用ミドルウェアをAppHttpKernelで定義 • ミドルウェアは、次のミドルウェアを呼ぶ • 一つの処理を行うミドルウェアを重ねていく
  • 23.
    Middleware public function handle($request,Closure $next)
 {
 if ($this->auth->check()) {
 return new RedirectResponse(url('/home'));
 }
 
 return $next($request);
 } ログイン済みなら、/homeへリダイレクト そうで無ければ、次のミドルウェアを呼ぶ
  • 24.
  • 25.
  • 26.
    Trait (c) 2015 MasashiShinbara @shin1x1 • AuthControllerとPasswordController • コンストラクタのみで、実処理はトレイトに実装 • 独自コントローラにもトレイトを再利用できる
  • 27.
    Trait public function getRegister()
 {
 returnview('auth.register');
 }
 
 public function postRegister(Request $request)
 {
 $validator = $this->registrar->validator($request->all());
 
 if ($validator->fails())
 {
 $this->throwValidationException(
 $request, $validator
 );
 }
 
 $this->auth->login($this->registrar->create($request->all()));
 
 return redirect($this->redirectPath());
 } method
  • 28.
    Trait public function getRegister()
 {
 returnview('auth.register');
 }
 
 public function postRegister(Request $request)
 {
 $validator = $this->registrar->validator($request->all());
 
 if ($validator->fails())
 {
 $this->throwValidationException(
 $request, $validator
 );
 }
 
 $this->auth->login($this->registrar->create($request->all()));
 
 return redirect($this->redirectPath());
 } method injection
  • 29.
    Service (c) 2015 MasashiShinbara @shin1x1
  • 30.
    Service (c) 2015 MasashiShinbara @shin1x1 • コントローラから起動
 (コントローラ以外からの呼び出しも可) • ビジネスロジックを実装 • 永続化などは、Eloquent(モデル)に移譲 • GuardクラスとRegistrarクラス
  • 31.
    Service - Registrar classRegistrar implements RegistrarContract
 {
 public function validator(array $data)
 {
 return Validator::make($data, [
 'name' => 'required|max:255',
 'email' => 'required|email|max:255|unique:users',
 'password' => 'required|confirmed|min:6',
 ]);
 }
 
 public function create(array $data)
 {
 return User::create([
 'name' => $data['name'],
 'email' => $data['email'],
 'password' => bcrypt($data['password']),
 ]);
 }
 } validator builder
  • 32.
    Service - Registrar classRegistrar implements RegistrarContract
 {
 public function validator(array $data)
 {
 return Validator::make($data, [
 'name' => 'required|max:255',
 'email' => 'required|email|max:255|unique:users',
 'password' => 'required|confirmed|min:6',
 ]);
 }
 
 public function create(array $data)
 {
 return User::create([
 'name' => $data['name'],
 'email' => $data['email'],
 'password' => bcrypt($data['password']),
 ]);
 }
 } business logic
  • 33.
    Controller(with Trait) public functionpostRegister(Request $request)
 {
 $validator = $this->registrar->validator($request->all());
 
 if ($validator->fails())
 {
 $this->throwValidationException(
 $request, $validator
 );
 }
 
 $this->auth->login($this->registrar->create($request->all()));
 
 return redirect($this->redirectPath());
 } call service call servicecall service
  • 34.
  • 35.
    Model(Eloquent) (c) 2015 MasashiShinbara @shin1x1 • Contracts(インターフェース)を実装 • プロパティ定義のみ • 実処理は、トレイトに実装
  • 36.
    Model(Eloquent) class User extendsModel implements AuthenticatableContract, CanResetPasswordContract
 {
 use Authenticatable, CanResetPassword;
 protected $table = 'users';
 protected $fillable = ['name', 'email', 'password'];
 protected $hidden = ['password', 'remember_token'];
 } Contract(interface) Trait
  • 37.
  • 38.
    まとめ (c) 2015 MasashiShinbara @shin1x1 • 認証実装は、良いサンプル実装 • 役割を分け、シンプルな実装を • こうしないといけないわけじゃない • Laravelの実装で、アーキテクチャを学ぶ
  • 39.
    @shin1x1 (c) 2015 MasashiShinbara @shin1x1