3. Sentinel 2.0 用戶認證應用
安裝好 Sentinel 2.0後,我們要來建立用戶的認證功能,包括註冊、登入、忘記密碼以及密碼重置,這部分改動的較大,請記得自己備份....
我的權限群組可分為三種:系統管理員admin & 公司主管boss &公司員工user
員工的部分只要帳號有啟用就預設是user了,所以這部分暫時不理他,我們需要額外新增兩個role群組權限,來個別定義這兩個權限的內容。
首先,我們先到Kernel去註冊中介層的路由名稱,方便我們直接透過路由來限制存取。
開啟 app/Http/Kernel.php,新增admin & boss 的role權限
新增 app/Http/Middleware/SentinelAdminAccess.php
開啟 app/Http/Middleware/SentinelBossAccess.php
接下來,我們要來設定所有用戶的登入認證與授權
開啟 app/Http/Middleware/Authenticate.php
開啟 app/Http/Controllers/Auth/PasswordController.php
然後我們就可以設定相關的路由定義了
開啟 app/Http/routes.php
產生資料填充檔
這裏我們新增了兩筆資料,admin的權限為最大,公司主管只能使用 user.user_manage
開啟 database/seeds/RoleTableSeeder.php
開啟 database/seeds/UserTableSeeder.php
開啟 database/seeds/DatabaseSeeder.php
執行資料填充:
最後我們需要新增相關的視圖:
新增 resources/views/auth/login.blade.php
新增 resources/views/auth/register.blade.php
新增 resources/views/auth/password.blade.php
新增 resources/views/auth/reset.blade.php
新增 resources/views/emails/password.blade.php
新增 resources/views/emails/verify.blade.php
新增 resources/views/errors/validation.blade.php
再來就用這三個帳號來測試登入以及可用的權限吧,記得要有 HomeController.php 喔!
P.S.
如何加入用戶的登入IP
users table:
$table->string('ip_address')->nullable();
open: /vendor/cartalyst/sentinel/src/Users/IlluminateUserRepository.php
find:
add after:
find :
add after :
我的權限群組可分為三種:系統管理員admin & 公司主管boss &公司員工user
員工的部分只要帳號有啟用就預設是user了,所以這部分暫時不理他,我們需要額外新增兩個role群組權限,來個別定義這兩個權限的內容。
首先,我們先到Kernel去註冊中介層的路由名稱,方便我們直接透過路由來限制存取。
開啟 app/Http/Kernel.php,新增admin & boss 的role權限
/** * The application's route middleware. * * @var array */ protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'admin' => \App\Http\Middleware\SentinelAdminAccess::class, 'boss' => \App\Http\Middleware\SentinelBossAccess::class,
];
新增 app/Http/Middleware/SentinelAdminAccess.php
<?php
namespace App\Http\Middleware;
use Closure;
use Sentinel;
class SentinelAdminAccess
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// First make sure there is an active session
if (!Sentinel::check()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest(route('auth.login'));
}
}
// Now check to see if the current user has the 'Admin' permission
if (!Sentinel::getUser()->inRole('Admin')) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return back()->withInput()->withErrors(trans('auth.user.noaccess'));
}
}
// All clear - we are good to move forward
return $next($request);
}
}
開啟 app/Http/Middleware/SentinelBossAccess.php
<?php
namespace App\Http\Middleware;
use Closure;
use Sentinel;
use Session;
class SentinelBossAccess
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// First make sure there is an active session
if (!Sentinel::check()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest(route('auth.login'));
}
}
// Now check to see if the current user has the 'Boss' permission
if (!Sentinel::getUser()->inRole('Boss')) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
Session::flash('error', trans('auth.user.noaccess'));
return redirect()->route('auth.login');
}
}
// All clear - we are good to move forward
return $next($request);
}
}
接下來,我們要來設定所有用戶的登入認證與授權
開啟 app/Http/Middleware/Authenticate.php
<?php
namespace App\Http\Middleware;
use Closure;
use Sentinel;
class Authenticate
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Sentinel::guest()){
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
開啟 app/Http/Controllers/Auth/PasswordController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Input;
use Validator;
use Sentinel;
use Reminder;
use Mail;
class PasswordController extends Controller
{
/*
* views模板頁面-忘記密碼
*/
public function getReminder() {return view('auth.password'); }
/*
* views模板頁面-重置密碼
*/
public function getReset(){return view('auth.reset'); }
/**
* 忘記密碼
*
* @param array $data
* @return User
*/
public function postReminder()
{
$input = Input::all();
// 驗證欄位
$rules = [
'email' => 'required|email|max:255',
];
$validation = Validator::make($input, $rules);
if ($validation->fails()) {
return back()->withErrors($validation)->withInput();
}
$user = Sentinel::findByCredentials($input);
if(!$user){
return back()->withErrors(trans('auth.password.email_fail'))->withInput();
}
$reminder = Reminder::exists($user) ?: Reminder::create($user);
$code = $reminder->code;
$sent = Mail::send('emails.password', compact('user', 'code'), function($m) use ($user) {
$m->to($user->email)->subject(trans('auth.password.email_title'));
});
// 寄送帳號驗證信失敗
if ($sent === 0) {
return redirect()->route('auth.register')->withErrors(trans('auth.password.send_fail'));
}
return back()->withSuccess(trans('auth.password.send_success'));
}
/**
* 變更密碼
*
* @param array $data
* @return User
*/
public function postReset()
{
$input = Input::all();
$rules = [
'email' => 'required|email|max:255',
'password' => 'required|confirmed|min:6',
];
$validation = Validator::make($input, $rules);
if ($validation->fails()) {
return back()->withErrors($validation)->withInput();
}
$user = Sentinel::findByCredentials($input);
if(!$user){
return back()->withErrors(trans('auth.password.email_fail'))->withInput();
}
$user = $this->update($user, $input);
return redirect()->route('auth.login')
->withSuccess(trans('password_success'));
}
/*
* Once you have authenticated, a session has been created.
* At this point you'll most likely want to do something with the users meta data.
*/
public function update($user, $input)
{
return Sentinel::update($user, $input);
}
}
然後我們就可以設定相關的路由定義了
開啟 app/Http/routes.php
// 認證路由 Route::group(['prefix' => 'auth', 'namespace' => 'Auth'], function () { // 登入路由 Route::get('login', ['as' => 'auth.login', 'uses' => 'AuthController@getLogin']); Route::post('login', ['as' => 'auth.login', 'uses' => 'AuthController@postLogin']); // 註冊路由 Route::get('register', ['as' => 'auth.register', 'uses' => 'AuthController@getRegister']); Route::post('register', ['as' => 'auth.register', 'uses' => 'AuthController@postRegister']); // 登出路由 Route::get('logout', ['as' => 'auth.logout', 'uses' => 'AuthController@getLogout']); // 驗證信箱路由 Route::get('verify/{id}/{code}', ['as' => 'auth.verify', 'uses' => 'AuthController@getConfirm']); }); // 重設密碼路由 Route::group(['prefix' => 'password',
'namespace' => 'Auth'], function () { // 申請密碼重置的路由 Route::get('email', ['as' => 'password.email', 'uses' => 'PasswordController@getReminder']); Route::post('email', ['as' => 'password.email', 'uses' => 'PasswordController@postReminder']); // 密碼重置的路由 Route::get('reset/{id}/{code}', ['as' => 'password.reset', 'uses' => 'PasswordController@getReset']); Route::post('reset', ['as' => 'password.reset', 'uses' => 'PasswordController@postReset']); }); // 前台首頁 Route::get('/', function () {return view('welcome'); }); // 後台首頁路由 Route::group(['prefix' => 'admin', 'namespace' => 'Admin',
'middleware' => 'auth'
], function () { Route::group([
'middleware' => '
admin
'
], function (){ Route::get('system_manage', ['as' => 'admin.system_manage', 'uses' => 'HomeController@index']); }); Route::group([
'middleware' => '
boss
'
], function (){ Route::get('user_manage', ['as' => 'admin.permission_manage', 'uses' => 'HomeController@index']); }); // 一般員工只能看到這頁 Route::get('/', ['as' => 'admin.root', 'uses' => 'HomeController@index']); });
產生資料填充檔
$
php artisan make:seeder RoleTableSeeder
$
php artisan make:seeder UserTableSeeder
這裏我們新增了兩筆資料,admin的權限為最大,公司主管只能使用 user.user_manage
開啟 database/seeds/RoleTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class RoleTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('roles')->delete();
Sentinel::getRoleRepository()->createModel()->create([
'name' => '系統管理員',
'slug' => 'Admin',
'permissions' => $this->Admin(),
]);
Sentinel::getRoleRepository()->createModel()->create([
'name' => '公司管理員',
'slug' => 'Boss',
'permissions' => $this->Boss(),
]);
}
private function Admin(){
return $data = array(
'user.user_manage' => true,
'sys.system_manage' => true,
'sys.rorle_manage' => true,
'sys.permission_manage' => true,
'sys.news_manage' => true,
);
}
private function Boss(){
$data = $this->Admin();
$data['sys.system_manage'] = false;
$data['sys.rorle_manage'] = false;
$data['sys.permission_manage'] = false;
$data['sys.news_manage'] = false;
return $data;
}
}
開啟 database/seeds/UserTableSeeder.php
<?php
use Illuminate\Database\Seeder;
class UserTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('users')->delete();
DB::table('role_users')->delete();
DB::table('activations')->delete();
$user = Sentinel::create([
'email' => 'admin@abc.com',
'first_name' => '系統管理員',
'password' => '111111',
]);
// 啟用帳號
$activation = Activation::create($user);
Activation::complete($user, $activation->code);
// Assign a user to a role.
$role = Sentinel::findRoleBySlug('Admin');
$role->users()->attach($user);
$user = Sentinel::create([
'email' => 'boss@abc.com',
'first_name' => '公司管理員',
'password' => '111111',
]);
// 啟用帳號
$activation = Activation::create($user);
Activation::complete($user, $activation->code);
// Assign a user to a role.
$role = Sentinel::findRoleBySlug('SuUser');
$role->users()->attach($user);
Sentinel::create([
'email' => 'user@abc.com',
'first_name' => '公司員工',
'password' => '111111',
]);
// 啟用帳號
$activation = Activation::create($user);
Activation::complete($user, $activation->code);
}
}
開啟 database/seeds/DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Model::unguard();
$this->call(RoleTableSeeder::class);
$this->call(UserTableSeeder::class);
Model::reguard();
}
}
執行資料填充:
$
php artisan db:seed
最後我們需要新增相關的視圖:
新增 resources/views/auth/login.blade.php
<form class="login-form" action="/auth/login" method="post">
{!! csrf_field() !!}
<h3 class="form-title">{{trans('auth.user.login')}}</h3>
@include('errors.validation')
<div class="form-group">
<!--ie8, ie9 does not support html5 placeholder, so we just show field title for that-->
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.email')}}</label>
<input class="form-control form-control-solid placeholder-no-fix" type="email" autocomplete="off" placeholder="{{trans('auth.user.email')}}" name="email" value="{{ old('email') }}" />
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.password')}}</label>
<input class="form-control form-control-solid placeholder-no-fix" type="password" autocomplete="off" placeholder="{{trans('auth.user.password')}}" name="password" id="password" />
</div>
<div class="form-actions">
<button type="submit" class="btn btn-success uppercase">{{trans('auth.user.btn_login')}}</button>
<label class="rememberme check">
<input type="checkbox" name="remember"> {{trans('auth.user.remember')}} </label>
<a href="{{ url('/password/email') }}" class="forget-password">{{trans('auth.user.forgot')}}</a>
</div>
{{-- @include('partials.social.authSocial') --}}
<div class="create-account">
<p>
<a href="{{ url('/auth/register') }}" class="uppercase">{{trans('auth.user.register')}}</a>
</p>
</div>
</form>
新增 resources/views/auth/register.blade.php
<form action="/auth/register" method="post">
{!! csrf_field() !!}
<h3>{{trans('auth.user.register')}}</h3>
@include('errors.validation')
<div class="form-group">
<!--ie8, ie9 does not support html5 placeholder, so we just show field title for that-->
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.email')}}</label>
<input class="form-control placeholder-no-fix" type="email" placeholder="{{trans('auth.user.email')}}" name="email" value="{{ old('email') }}"/>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.first_name')}}</label>
<input class="form-control placeholder-no-fix" type="text" placeholder="{{trans('auth.user.first_name')}}" name="first_name" value="{{ old('first_name') }}" />
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.last_name')}}</label>
<input class="form-control placeholder-no-fix" type="text" autocomplete="off" placeholder="{{trans('auth.user.last_name')}}" name="last_name" value="{{ old('last_name') }}"/>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.password')}}</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" id="register_password" placeholder="{{trans('auth.user.password')}}" name="password"/>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.password_confirm')}}</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="{{trans('auth.user.password_confirm')}}" name="password_confirmation"/>
</div>
<div class="form-actions">
<a href="{{ url('/auth/login') }}">
<button type="button" id="register-back-btn" class="btn btn-default">{{trans('auth.user.btn_back')}}</button>
</a>
<button type="submit" id="register-submit-btn" class="btn btn-success uppercase pull-right">{{trans('auth.user.btn_register')}}</button>
</div>
</form>
新增 resources/views/auth/password.blade.php
<form action="/password/email" method="post">
{!! csrf_field() !!}
<h3>{{trans('auth.password.title')}}</h3>
@include('errors.validation')
<p> {{trans('auth.password.desc')}}</p>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.email')}}</label>
<input class="form-control placeholder-no-fix" type="email" autocomplete="off" placeholder="{{trans('auth.user.email')}}" name="email" value="{{ old('email') }}"/>
</div>
<div class="form-actions">
<a href="{{ url('/auth/login') }}">
<button type="button" id="back-btn" class="btn btn-default">{{trans('auth.user.btn_back')}}</button>
</a>
<button type="submit" class="btn btn-success uppercase pull-right">{{trans('auth.password.submit')}}</button>
</div>
</form>
新增 resources/views/auth/reset.blade.php
<form action="/password/reset" method="post">
{!! csrf_field() !!}
<h3>{{trans('auth.reset.title')}}</h3>
@include('errors.validation')
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.user.email')}}</label>
<input class="form-control placeholder-no-fix" type="email" autocomplete="off" placeholder="{{trans('auth.user.email')}}" name="email" value="{{ old('email') }}"/>
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.reset.password')}}</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="{{trans('auth.reset.password')}}" name="password" />
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">{{trans('auth.reset.password_confirmation')}}</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="{{trans('auth.reset.password_confirmation')}}" name="password_confirmation" />
</div>
<div class="form-actions">
<button type="submit" class="btn btn-success uppercase pull-right">{{trans('auth.reset.submit')}}</button>
</div>
</form>
新增 resources/views/emails/password.blade.php
<!-- resources/views/emails/password.blade.php -->
<h2>{{trans('auth.password.email_title')}}</h2>
<div>{{trans('auth.password.email_content')}}</div>
<div>{{ url('password/reset/'.$user->getUserId().'/'.$code) }}</div>
新增 resources/views/emails/verify.blade.php
<!-- resources/views/emails/verify.blade.php -->
<h2>{{trans('auth.verify.email_title')}}</h2>
<div>{{trans('auth.verify.email_content')}}</div>
<div>{{ url('auth/verify/'.$user->getUserId().'/'.$code) }}</div>
新增 resources/views/errors/validation.blade.php
<!-- resources/views/errors/validation.blade.php -->
@if ($errors->any())
<div class="alert alert-danger">
<button class="close" data-close="alert"></button>
@foreach ($errors->all() as $error)
<div>{{ $error }}</div>
@endforeach
</div>
@endif
再來就用這三個帳號來測試登入以及可用的權限吧,記得要有 HomeController.php 喔!
P.S.
如何加入用戶的登入IP
users table:
$table->string('ip_address')->nullable();
open: /vendor/cartalyst/sentinel/src/Users/IlluminateUserRepository.php
find:
namespace Cartalyst\Sentinel\Users;
add after:
use Illuminate\Support\Facades\Request;
find :
$user->last_login = Carbon::now();
add after :
$user->ip_address = Request::ip();
Hi 您好
回覆刪除再使用 inRole 時有沒有需要注意什麼?
我在使用時噴出了
BadMethodCallException in Builder.php line 2071:
Call to undefined method Illuminate\Database\Query\Builder::getRoleId()
sentinel ver 2.0.8