laravel-5-boilerplateのルーティングの続きです
以前の記事で app/Http/route.php は読めたので、
次は app/Http/Routes/Backend/Access.php を読み進めます
//app/Http/Routes/Backend/Access.php
<?php
Route::group([
'prefix' => 'access',
'namespace' => 'Access',
'middleware' => 'access.routeNeedsPermission:view-access-management',
], function() {
/**
* User Management
*/
Route::group(['namespace' => 'User'], function() {
Route::resource('users', 'UserController', ['except' => ['show']]);
Route::get('users/deactivated', 'UserController@deactivated')->name('admin.access.users.deactivated');
Route::get('users/deleted', 'UserController@deleted')->name('admin.access.users.deleted');
Route::get('account/confirm/resend/{user_id}', 'UserController@resendConfirmationEmail')->name('admin.account.confirm.resend');
/**
* Specific User
*/
Route::group(['prefix' => 'user/{id}', 'where' => ['id' => '[0-9]+']], function() {
Route::get('delete', 'UserController@delete')->name('admin.access.user.delete-permanently');
Route::get('restore', 'UserController@restore')->name('admin.access.user.restore');
Route::get('mark/{status}', 'UserController@mark')->name('admin.access.user.mark')->where(['status' => '[0,1]']);
Route::get('password/change', 'UserController@changePassword')->name('admin.access.user.change-password');
Route::post('password/change', 'UserController@updatePassword')->name('admin.access.user.change-password');
});
});
/**
* Role Management
*/
Route::group(['namespace' => 'Role'], function() {
Route::resource('roles', 'RoleController', ['except' => ['show']]);
});
/**
* Permission Management
*/
Route::group(['prefix' => 'roles', 'namespace' => 'Permission'], function() {
Route::resource('permission-group', 'PermissionGroupController', ['except' => ['index', 'show']]);
Route::resource('permissions', 'PermissionController', ['except' => ['show']]);
Route::group(['prefix' => 'groups'], function() {
Route::post('update-sort', 'PermissionGroupController@updateSort')->name('admin.access.roles.groups.update-sort');
});
});
});
Laravelのルーティングの基本
ルートの名前
Route::get('users/deactivated', 'UserController@deactivated')->name('admin.access.users.deactivated');
各ルートに名前をつけることができます
名前を設定すると redirect時などに route('admin.access.users.deactivated')でアクセスできるようになります
Route::resource
Route::resource('users', 'UserController', ['except' => ['show']]);
これで以下のようにコントローラーにアクセスされます
namespace App\Controllers;
class helloController extends BaseController
{
// getでusers/にアクセスされた場合
public function index()
{
〜
}
// getでusers/createにアクセスされた場合
public function create()
{
〜
}
// postでusers/にアクセスされた場合
public function store()
{
〜
}
//などなど
}
詳しくはこちらの記事で解説されています
http://qiita.com/michiomochi@github/items/de19c560bc1dc19d698c
解説
まず、ルートグループで以下が設定されています
ルートのプレフィックスに /admin を利用
名前空間が App\Http\Controllers\Language~~ のコントローラーを利用
ミドルウェア access.routeNeedsPermission:view-access-management を利用
app/Http/Kernel.phpを見に行きます
//app/Http/Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// 省略
protected $routeMiddleware = [
// 省略
'access.routeNeedsRole' => \App\Http\Middleware\RouteNeedsRole::class,
'access.routeNeedsPermission' => \App\Http\Middleware\RouteNeedsPermission::class,
];
ミドルウェア名 access.routeNeedsPermission は
app/Http/Middleware/RouteNeedsPermissionを読み込んでいることがわかります
//app/Http/Middleware/RouteNeedsPermission.php
<?php
namespace App\Http\Middleware;
use Closure;
class RouteNeedsPermission
{
public function handle($request, Closure $next, $permission)
{
if (! access()->allow($permission)) {
return redirect()
->route('frontend.index')
->withFlashDanger(trans('auth.general_error'));
}
return $next($request);
}
}
このミドルウェアでは以下のことを行っています
-
$request
と$permission
を受け取る -
access()->allow($permission)
を評価する - route('frontend.index')へリダイレクトさせる or 次のミドルウェアへ進める
では、access()->allow($permission)
の中身を見に行きます
access()はヘルパー関数です
Laravelデフォルトのものではなさそうなのでapp/helper.phpを確認します
<?php
//省略
if (! function_exists('access')) {
/**
* Access (lol) the Access:: facade as a simple function
*/
function access()
{
return app('access');
}
}
//省略
ありましたね
では次は app/Providers/AccessServiceProvider.php を確認
<?php
namespace App\Providers;
use App\Services\Access\Access;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
/**
* Class AccessServiceProvider
* @package App\Providers
*/
class AccessServiceProvider extends ServiceProvider
{
//省略
private function registerAccess()
{
$this->app->bind('access', function ($app) {
return new Access($app);
});
}
//省略
}
app/Services/Access.phpが正体ですね、見てみましょう
//app/Services/Access
<?php
namespace App\Services\Access;
class Access
{
public $app;
public function __construct($app)
{
$this->app = $app;
}
public function user()
{
return auth()->user();
}
//省略
public function allow($permission)
{
if ($user = $this->user()) {
return $user->allow($permission);
}
return false;
}
//省略
}
allowメソッドは以下の作業を行います
ログイン中のユーザーのUserクラスのインスタンスを取得し、
$user->allow($permission)
でパーミッションを所持しているか確認
ユーザーがログインしており、かつ求められたパーミッションを所有している場合のみtrueを返す
では、$user->allow()
を見に行きます
userクラスはapp/Models/Access/User.phpに記述されています
//app/Models/Access/User.php
<?php
namespace App\Models\Access\User;
use App\Models\Access\User\Traits\UserAccess;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Models\Access\User\Traits\Attribute\UserAttribute;
use App\Models\Access\User\Traits\Relationship\UserRelationship;
class User extends Authenticatable
{
use SoftDeletes, UserAccess, UserAttribute, UserRelationship;
protected $guarded = ['id'];
protected $hidden = ['password', 'remember_token'];
protected $dates = ['deleted_at'];
}
allow()が定義されてないませんが、
これは trait (トレイト)として app/Models/Access/User/Traits/UserAccess.phpを読み込んでいるからです
//app/Models/Access/User/Traits/UserAccess.php
<?php
namespace App\Models\Access\User\Traits;
/**
* Class UserAccess
* @package App\Models\Access\User\Traits
*/
trait UserAccess
{
//省略
public function allow($nameOrId)
{
foreach ($this->roles as $role) {
//See if role has all permissions
if ($role->all) {
return true;
}
// Validate against the Permission table
foreach ($role->permissions as $perm) {
//First check to see if it's an ID
if (is_numeric($nameOrId)) {
if ($perm->id == $nameOrId) {
return true;
}
}
//Otherwise check by name
if ($perm->name == $nameOrId) {
return true;
}
}
}
//Check permissions directly tied to user
foreach ($this->permissions as $perm) {
//First check to see if it's an ID
if (is_numeric($nameOrId)) {
if ($perm->id == $nameOrId) {
return true;
}
}
//Otherwise check by name
if ($perm->name == $nameOrId) {
return true;
}
}
return false;
}
//省略
}
ありました!
詳しくは解説しませんが、ログイン中のユーザーがパーミッションを持っているかforeachでループしながら確認しています。
長くなりましたが、これがミドルウェアaccess.routeNeedsPermissionの正体です
もう一度、app/Http/Routes/Backend/Access.phpを確認します
//app/Http/Routes/Backend/Access.php
<?php
Route::group([
'prefix' => 'access',
'namespace' => 'Access',
'middleware' => 'access.routeNeedsPermission:view-access-management',
], function() {
/*
* ルーティング
*/
});
access.routeNeedsPermissionにview-access-managementを渡しています
これはミドルウェアaccess.routeNeedsPermission側で$permissionとして受けとり処理を行います
とりあえず以上
気が向いたら追記します