Laravel 基礎(chǔ)學(xué)習(xí) 第四天

完成賬戶信息修改功能

  • 利用 resource 路由為我們提供的路由: 'user.edit'載入修改資料的界面 和 'user.update'完成修改的邏輯
  • 編輯對(duì)應(yīng)方法 UserController@edit 載入視圖
public function edit(User $user) //這里通過(guò)依賴注入實(shí)例化了 $user
{
    return view('user.edit', compact('user')); //這里將 $user 傳給視圖
}
  • 編輯視圖處理 : 記得偽造為 method="PATCH" 的表單
@extends('layouts.master') 

@section('title', '修改資料') 

@section('content')
<div class="container">
    <h1 class="text-center">修改資料</h1>
    @include('components._error', ['errors' => $errors])

    <form method="POST" action=" {{ route('user.update', $user->id) }} ">
        {{-- 重點(diǎn): 因?yàn)?user.update 路由要求method="PUT/PATCH" 但是普通form并不支持穴翩,所以需要我們自己添加一個(gè) input.hidden 表單項(xiàng)來(lái)偽造 --}}
        @method('PATCH')
        @csrf
        <div class="form-group">
            <label for="name">用戶名</label>
            <input type="text" class="form-control" id="name" placeholder="請(qǐng)輸入用戶名" name="name" value="{{ old('name') ? old('name') : $user->name }}">
            {{-- 這里是判斷 old('name') 是否有值叼风,如果沒(méi)有扼菠,就用我們傳過(guò)來(lái)的$user --}}
        </div>
        <div class="form-group">
            <label for="password">新密碼</label>
            <input type="password" class="form-control" id="password" placeholder="請(qǐng)輸入密碼" name="password">
            <input type="password" class="form-control" placeholder="請(qǐng)?jiān)诖溯斎朊艽a以確認(rèn)" name="password_confirmation">
        </div>
        <button type="rest" class="btn btn-secondary">重置</button>
        <button type="submit" class="btn btn-primary">修改</button>
    </form>
</div>
@endsection
  • 在 _navbar.blade.php 綁定一個(gè)跳轉(zhuǎn)到編輯頁(yè)面的超鏈接 Auth::id() 獲取當(dāng)前登陸用戶的主鍵id
<a href="{{ route('user.edit', Auth::id()) }}" class="btn btn-outline-success"> {{ Auth::user()->name }} </a>
  • 完善 UserController@update 更新數(shù)據(jù)庫(kù)中的用戶信息
public function update(UserRequest $request, User $user)
{
    // ...
}
  • 上面有兩個(gè)坑: 第一個(gè)是 User $user => 路由要求我們得傳修改數(shù)據(jù)的主鍵進(jìn)來(lái)坦刀! => 因此表單上 <form ... action=" {{ route('user.update', $user->id) }} ">
  • 第二個(gè)就是使用 UserRequest $request 驗(yàn)證數(shù)據(jù)的時(shí)候洽议,會(huì)報(bào)錯(cuò)“郵箱沒(méi)填虏肾,用戶名重復(fù)等...”
return [
    'name' => 'required|min:8|max:32|unique:users,name,' . Auth::id(), // unique:表,字段,排除校驗(yàn)自己
    'email' => 'sometimes|required|email|unique:users', // sometimes 只有在表單提交的數(shù)據(jù)中履恩,存在 email 字段時(shí)校驗(yàn)
    'password' => 'required|min:8|confirmed'
];
  • 最后我還是覺(jué)得這種太麻煩了甸祭,我不如自己再新建一個(gè) Request 來(lái)完成關(guān)于 “更新邏輯” 的驗(yàn)證 php artisan make:request UserEditRequest 編輯 UserEditRequest@rule 并將 UserRequest 還原
public function rules()
    {
        return [
            'name' => 'required|min:8|max:32|unique:users,name,' . Auth::id(),
            'password' => 'nullable|min:8|confirmed'
        ];
    }
  • 完善功能 UserController@update
public function update(UserEditRequest $request, User $user) // 這里通過(guò) UserEditRequest 驗(yàn)證
{
    // 判斷是否修改過(guò)用戶名或者密碼
    if($request->name == $user->name || Hash::check($request->password, $user->password)) { // Hash::check(v1, v2) 判斷v1加密后是否等于v2
        session()->flash('danger', '您未修改任何內(nèi)容');
        return redirect()->back();
    }
    // 處理數(shù)據(jù)
    $data['name'] = $request->name;
    if($request->password) {
        $data['password'] = Hash::make($request->password);
    }
    // 執(zhí)行更新和跳轉(zhuǎn)
    $user->update($data);
    session()->flash('success', '編輯資料成功!');
    return redirect()->route('user.show', [$user]);
}

用戶資料編輯總結(jié)

  • UserController@edit 展示編輯頁(yè)面善已, 在編輯頁(yè)面中需要使用 @method('PATCH') 來(lái)偽造表單的 action="PATCH" (因?yàn)槠胀?form 不支持patch)灼捂, 同時(shí)別忘了使用 input.value={{ old('name') ? old('name') : $user->name }} 來(lái)判斷是否 修改出錯(cuò),出錯(cuò)則用 old() 調(diào)出原來(lái)的值换团,沒(méi)出錯(cuò)就用 $user->name 顯示用戶名悉稠。
  • UserController@update 完成 “接受和驗(yàn)證數(shù)據(jù)->數(shù)據(jù)入庫(kù)->完成跳轉(zhuǎn)” 邏輯。
    • 接受和驗(yàn)證數(shù)據(jù)艘包,我們先開始通過(guò)編輯 UserRequest@rule 來(lái)重新設(shè)定驗(yàn)證規(guī)則的猛,但是非常繁瑣:
      • 'name' => '..|unique:users,name,'.Auth::id() => 排除唯一驗(yàn)證時(shí)沒(méi)修改name導(dǎo)致驗(yàn)證自己和自己重名
      • 'email' => 'sometimes|...' => 當(dāng)表單中有 email 時(shí)再驗(yàn)證...
    • 所以我們新建了一個(gè) Request 進(jìn)行驗(yàn)證 php artisan make:request UserEditRequest 耀盗, 只驗(yàn)證用戶名和密碼。 nullable 可以為空卦尊。
    public function rules()
    {
        return [
            'name' => 'required|min:8|max:32|unique:users,name,' . Auth::id(),
            'password' => 'nullable|min:8|confirmed'
        ];
    }
    
    • update() 方法需要2個(gè)參數(shù)叛拷,第一個(gè)就是我們上面驗(yàn)證的,第二個(gè)則是修改用戶的主鍵id猫牡,我們可以通過(guò) Auth::id() 或者傳遞過(guò)去的$user $user->id 來(lái)獲取胡诗。因此 form.action="{{ route('user.update', $user->id) }}"
    • update() 方法中,我們需要判斷用戶是否修改了用戶名或者密碼之一淌友,然后需要處理要更新的數(shù)據(jù) $data 煌恢,判斷密碼是否為空,為空則不更新密碼震庭。最后使用 $user->update($data) 更新數(shù)據(jù)
    // 唯一需要注意的就是 Hash::check(用戶輸入的密碼, 經(jīng)過(guò)Hash加密的舊密碼) => 是將用戶輸入的密碼加密后 對(duì)比舊密碼瑰抵,如果兩者相同,則返回true
    

使用中間件 middleware 判斷用戶是否登陸

  • 定義構(gòu)造函數(shù): UserController@__contrusct
 public function __construct()
{
    $this->middleware('auth'); //調(diào)用 中間件auth 判斷用戶是否登陸
}
  • 這樣一來(lái)器联,用戶不登陸二汛,訪問(wèn)控制器內(nèi)的任何方法,都會(huì)被強(qiáng)制跳轉(zhuǎn)到登陸頁(yè)面拨拓,但是有一個(gè)問(wèn)題肴颊,注冊(cè)和新增用戶也會(huì)強(qiáng)制跳轉(zhuǎn)到登陸頁(yè)面,所以我們應(yīng)該使用 ...->except(['方法名1', '方法名2']) 排除那些不需要登陸就可以訪問(wèn)的方法
/**
    * 定義可以被公開訪問(wèn)(不需要登陸)的方法
    */
private $public = ['create', 'store'];

/**
    * 通過(guò)構(gòu)造函數(shù)調(diào)用中間件判斷用戶是否登陸
    */
public function __construct()
{
    // 調(diào)用中間件 “auth” 判斷用戶是否登陸 -> 排除(可以被公開訪問(wèn)的方法)
    $this->middleware('auth')->except($this->public);
}

使用 Policy 來(lái)控制權(quán)限

上面實(shí)現(xiàn)的編輯用戶資料的功能其實(shí)有很嚴(yán)重的權(quán)限錯(cuò)誤:應(yīng)該設(shè)置只能自己編輯自己渣磷!但是其實(shí)通過(guò)修改瀏覽器地址指向的url婿着,我們可以編輯所有其他的用戶。

  • 創(chuàng)建 Policy 策略 php artisan make:policy UserPolicy => 會(huì)在 /app/policies/ 下創(chuàng)建一個(gè) UserPplicy 文件
  • 但是這樣創(chuàng)建在接下來(lái)我們依然要去綁定模型和自己編寫方法醋界,太麻煩了竟宋,我們創(chuàng)建一個(gè)針對(duì) User 模型的策略。(即修改 users表的權(quán)限控制策略) php artisan make:policy UserPolicy --model=User形纺,查看它的內(nèi)部代碼
<?php

namespace App\Policies;

use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy
{
    use HandlesAuthorization; //引用trait

    public function view(User $user, User $model) //view策略
    {
        //
    }
    public function create(User $user) //create策略
    {
        //
    }
    public function update(User $user, User $model) //update策略
    {
        //
    }

    public function delete(User $user, User $model) //delete策略
    {
        //
    }
}

// 只要對(duì)應(yīng)的策略返回 true丘侠,則表明可以執(zhí)行接下來(lái)的操作。
  • 當(dāng)然現(xiàn)在這個(gè)東西是不可以直接使用的逐样!需要在 “服務(wù)提供商Providers” /app/Providers/ 下的 AuthServiceProvider 中注冊(cè)
protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
    'App\User' => 'App\policies\UserPolicy', //這里填寫UserPolicy的命名空間
];
  • 在控制器中調(diào)用策略進(jìn)行權(quán)限認(rèn)證 UserController@update authorize('驗(yàn)證方法名', 用戶)
public function update(UserEditRequest $request, User $user) // 這里通過(guò) UserEditRequest 驗(yàn)證
{
    // 判斷用戶是否在權(quán)限策略內(nèi)進(jìn)行操作(自己正在更新自己蜗字,而不是越權(quán)更新他人)
    $this->authorize('update', $user); //這里的 'update' 對(duì)應(yīng) UserPolicy@update, $user 對(duì)應(yīng) 當(dāng)前用戶 
    ...
}
  • 完善 UserPolicy@update 方法返回值為 true 則通過(guò)驗(yàn)證
public function update(User $user, User $model) //第一個(gè)參數(shù)表示當(dāng)前登陸的用戶,第二個(gè)參數(shù)表示被修改的用戶
{
    // 判斷當(dāng)前登陸的用戶是否為當(dāng)前被修改的用戶
    return $user == $model;
}

總結(jié) Policy 的使用

  • Policy 策略定義文件都在 /app/Policies/ 下
  • 創(chuàng)建 Policy 并指定該策略針對(duì)的模型 php artisan make:policy XxPolicy --model=Xx
  • 創(chuàng)建好的 Policy 里面的方法就是不同的權(quán)限認(rèn)證場(chǎng)景脂新,在控制器中使用 $this->authorize('方法名', 當(dāng)前用戶) 進(jìn)行調(diào)用秽澳。 一旦 方法() 返回true 則通過(guò)驗(yàn)證,因此在方法內(nèi)戏羽,我們需要進(jìn)行條件判斷
  • 創(chuàng)建好的 Policy 不可以直接使用,需要在 /app/Providers/ 內(nèi)注冊(cè)楼吃,這里我們是針對(duì)用戶權(quán)限的策略始花,因此需要在AuthServiceProvider 中注冊(cè)
protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
    'App\User' => 'App\policies\UserPolicy', // 模型命名空間 => 策略命名空間
];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妄讯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子酷宵,更是在濱河造成了極大的恐慌亥贸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浇垦,死亡現(xiàn)場(chǎng)離奇詭異炕置,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)男韧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門朴摊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人此虑,你說(shuō)我怎么就攤上這事甚纲。” “怎么了朦前?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵介杆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我韭寸,道長(zhǎng)春哨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任恩伺,我火速辦了婚禮赴背,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘莫其。我一直安慰自己癞尚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布乱陡。 她就那樣靜靜地躺著浇揩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪憨颠。 梳的紋絲不亂的頭發(fā)上胳徽,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音爽彤,去河邊找鬼养盗。 笑死,一個(gè)胖子當(dāng)著我的面吹牛适篙,可吹牛的內(nèi)容都是我干的往核。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嚷节,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼聂儒!你這毒婦竟也來(lái)了虎锚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤衩婚,失蹤者是張志新(化名)和其女友劉穎窜护,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體非春,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柱徙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奇昙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片护侮。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖敬矩,靈堂內(nèi)的尸體忽然破棺而出概行,到底是詐尸還是另有隱情,我是刑警寧澤弧岳,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布凳忙,位于F島的核電站,受9級(jí)特大地震影響禽炬,放射性物質(zhì)發(fā)生泄漏涧卵。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一腹尖、第九天 我趴在偏房一處隱蔽的房頂上張望柳恐。 院中可真熱鬧,春花似錦热幔、人聲如沸乐设。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)近尚。三九已至,卻和暖如春场勤,著一層夾襖步出監(jiān)牢的瞬間戈锻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工和媳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留格遭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓留瞳,卻偏偏與公主長(zhǎng)得像拒迅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353