Laravel:管理者のみに新規ユーザー登録(register)を許可
Laravel:register を管理者のみに限定にしたい
ずっと悩んでました。
今回のアプリは企業の基幹業務となる為、簡単にユーザー作られては困ります。
勝手にログインユーザー作られて、原価情報見られたなんて害しかありません。
と言うことで、ずっとregisterの振舞いを変えたかったのです。
でも、Auth関連はトレイトが多くどうすればいいかわからない。
【Illuminate\Foundation\】以降はあまり弄りたくないし...。
そんなこんなで後回しにしていましたが、やっと解決に至りました。
Laravelのバージョン情報取得
この記事を書くにあたり、様々なサイトで情報収集させていただきました。
管理者のみ新規ユーザー登録できるという構築の説明はLaravel5.2以前のものが多くHITし、お手本の通りにファイルが無い事もしばしば。その為、私の構築環境を明示しておきます。
Laravel Famework 5.5.44 だそうです。
レジスター動作の要求事項
作成する仕組みは下記要項を満たすものとします。
- 未認証(GUEST)の 新規ユーザー登録をガードする
- 未認証(GUEST)が register にアクセスした時、Login画面にリダイレクト
- 全ての認証ユーザーは自分の登録情報の変更が出来る
- 全ての認証ユーザーは他ユーザーの情報(氏名とメールアドレスのみ)を閲覧できる
- 管理者ユーザーは新規ユーザー登録が出来る
- 一般ユーザーの新規ユーザー登録をガードする
- 管理者ユーザーは全ユーザーの情報を変更可能とする
- 管理者ユーザーは全ユーザーのパスワード再設定を行える
- Engineer権限は全ての情報のアクセス、変更、新規登録、削除を可能とする
前提条件として、Gate機能の実装を済ませたものとします。
※Gateの実装はここら辺(サイト1、サイト2、サイト3)を参考に構築できます。
最初に結論から
下記設定にすると登録ユーザーのみ新規ユーザー登録が出来るようになります。
\app\Http\Auth\RegisterController.php 39行目あたりのコンストラクト
public function __construct()
{
$this->middleware('auth'); //元は $this->middleware('guest');
}
\routes\web.php の Auth::routes(); を削除(コメントアウト)します。
/*
|--------------------------------------------------------------------------
| ログイン処理
|--------------------------------------------------------------------------
*/
// Auth::routes();
//以降設定変更
Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
Route::post('login', 'Auth\LoginController@login');
Route::post('logout', 'Auth\LoginController@logout')->name('logout');
Route::get('/password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
Route::post('/password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
Route::get('/password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
Route::post('/password/reset', 'Auth\ResetPasswordController@reset');
/*
|-------------------------------------------------------------------------
| 管理者以上で操作
|-------------------------------------------------------------------------
*/
Route::group(['middleware' => ['auth', 'can:admin']], function () {
//ユーザー登録
Route::get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
Route::post('register', 'Auth\RegisterController@register');
});
Auth::routes(); は Laravel標準のAuth認証【laravel\vendor\laravel\framework\src\Illuminate\Routing\Router.php】を呼び出しています。
Route::group(['middleware' => ['auth', 'can:admin']], function () { hogehoge; }); はGateの設定が完了した後、adminで登録したユーザーに許可しますという関数になります。
ルートとログインのヘッダーからregisterを外すのを忘れない
上記設定が出来ていれば、Guestでregisterにアクセスした場合loginへリダイレクトされます。
でも未認証で触れる箇所に新規登録(register)があるのは気持ち良くないのでリンクを外します。
ルート【routes\web.php】でルートのビューを探します。
Route::get('/', function () {
return view('welcome');
});
私の場合はLaravel標準のwelcomeをそのまま閲覧しています。
ビュー【resources\views\welcome.blade.php】を確認します。
/* ビフォアー */
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@if (Auth::check())
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ url('/login') }}">Login</a>
<a href="{{ url('/register') }}">Register</a>
@endif
</div>
@endif
Registerありましたね。こいつを削除します。
/* アフター */
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@if (Auth::check())
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ url('/login') }}">Login</a>
<a href="{{ url('/register') }}">Register</a>
@endif
</div>
@endif
次にログインのヘッダーにあるRegisterを処理します。
【resources\views\auth\login.blade.php】を確認します。
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">ログイン</div>
ヘッダーはlayouts.appにある様です。【resources\views\layouts\app.blade.php】を確認します。
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-default navbar-static-top">
<div class="container">
<div class="navbar-header">
<!-- Collapsed Hamburger -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse" aria-expanded="false">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Branding Image -->
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
</div>
<div class="collapse navbar-collapse" id="app-navbar-collapse">
<!-- Left Side Of Navbar -->
<ul class="nav navbar-nav">
</ul>
<!-- Right Side Of Navbar -->
<ul class="nav navbar-nav navbar-right">
<!-- Authentication Links -->
@guest
<li><a href="{{ route('login') }}">Login</a></li>
<li><a href="{{ route('register') }}">Register</a></li>
@else
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false" aria-haspopup="true" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>
<a href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
Logout
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
{{ csrf_field() }}
</form>
</li>
</ul>
</li>
@endguest
</ul>
</div>
</div>
</nav>
@yield('content')
</div>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
47行目あたりにありました。ここからRegisterを削除します。
<ul class="nav navbar-nav navbar-right">
<!-- Authentication Links -->
@guest
<li><a href="{{ route('login') }}">Login</a></li>
@else
たったこれだけで最初に上げた項目【1,2,5,6】が実装できてしまいました。
Laravelおそるべし。
長くなったので update と delete については別記事で記載します。
まとめ
この機能の実装はトレイトを追ったりしかなり迷走しました。
だってねぇ、何やってもリダイレクトでhomeに戻ってきちゃうし。
肝は【\app\Http\Auth\RegisterController.php】の変更です。
解ると簡単なんですよね「今までの苦労は何だったんだ」と思う程度に。


