본문 바로가기

개발/PHP 라라벨

라라벨 비밀번호 재설정 - email 보내기 & 변경

현재 저의 프로젝트에는 일반사용자와 비즈니스사용자 두가지 이상의 계정(Auth::guard 사용)을 관리하고 있습니다.

라라벨의 관례에 의해 일반사용자(users - DB table)의 비밀번호 찾기 기능은 공식문서(https://laravel.kr/docs/5.6/passwords만 봐도 문제없이 기능 구현이 가능합니다.

 

하지만 한 프로젝트에서 두가지 이상의 계정을 관리하거나 커스텀한 계정 관리를 하고 있다면 해당 문서만으로는 부족합니다.

 

패스워드 재설정을 하기위해서는 password_resets 테이블이 필요합니다. 아래의 명령어로 데이터베이스 마이그레이션을 해줍니다. (라라벨에 기본 장착된 사용자인증을 사용하고 있다면 이미 추가되어 있을것입니다.)

 

php artisan migrate

 

 

하지만 저는 일반사용자 관리를 위해 해당 테이블을 이미 쓰고 있으므로 password_resets 와 똑같은 컬럼을 가진password_resets_biz 라는 테이블을 임의로 생성하였습니다.

 

php artisan make:auth

 

위의 명령어를 실행하면 라우터와 비밀번호 재설정을 위한 resources/views/auth/password 폴더안에 뷰가 자동 생성되지만 뷰를 사용하지 않아서 삭제했습니다.

 

Controllers/Auth 폴더내에 ForgotPasswordController.php 와 ResetPasswordController.php 가 자동 생성되어 있을것입니다. ForgotPasswordController는 비밀번호를 생성할 수 있는 링크를 포함한 메일을 보내주는 역할을 하고 ResetPasswordController는 링크를 클릭하면 재설정 할수 있는 화면을 생성하고 실제 비밀번호를 저장하는 역할을 하고 있습니다.

 

저는 이미 해당 컨트롤러를 일반사용자 관리를 위해 사용하고 있기때문에 이름이 비슷한 컨트롤러 두개를 더 생성해 주었습니다. BizForgotPasswordController.php BizResetPasswordController.php

 

어떤 사용자 테이블을 사용할지 선택하기 위해 broker 함수를 재정의 합니다.

실제 SendsPasswordResetEmails 내에 broker 함수가 있는데 재정의 하게 되면 재정의 함수가 우선 바인딩되고 없을 경우 SendsPasswordResetEmails 내의 broker 함수가 바인딩 되는것을 확인했습니다.

 

BizForgotPasswordController.php 내용

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Support\Facades\Password;

class BizForgotPasswordController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Password Reset Controller
    |--------------------------------------------------------------------------
    |
    | This controller is responsible for handling password reset emails and
    | includes a trait which assists in sending these notifications from
    | your application to your users. Feel free to explore this trait.
    |
    */

    use SendsPasswordResetEmails;

    /**
     * Create a new controller instance.
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    // 어떤 사용자 테이블을 사용할지 결정하는 broker 함수를 재정의합니다.
    public function broker()
    {
        return Password::broker('biz');
    }
}

 

재설정 할수 있는 화면을 생성하고 실제 비밀번호를 저장하는 역할을 하는 BizResetPasswordController도 broker 함수 재정의가 필요합니다. 또한 비밀번호를 어느 테이블에 저장할지 커스텀한 선택을 하기 위해 guard 도 재정의가 필요합니다.

 

BizResetPasswordController.php 내용

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Password;

class BizResetPasswordController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Password Reset Controller
    |--------------------------------------------------------------------------
    |
    | This controller is responsible for handling password reset requests
    | and uses a simple trait to include this behavior. You're free to
    | explore this trait and override any methods you wish to tweak.
    |
    */

    use ResetsPasswords;

    /**
     * Where to redirect users after resetting their password.
     *
     * @var string
     */
    protected $redirectTo = '/biz/login';

    /**
     * Create a new controller instance.
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get the broker to be used during password reset.
     *
     * @return PasswordBroker
     */
    public function broker()
    {
        return Password::broker('biz');
    }

    protected function guard()
    {
        return Auth::guard('biz');
    }

    public function showResetPassword(Request $request, $token = null)
    {
        return view('biz.resetPw')->with([
            'token' => $token,
            'title' => '비밀번호 재설정'
            ]);
    }
}

 

실제 ResetsPasswords trait 내에는 재설정 하는 화면을 생성해주는 함수(showResetForm)가 포함되어 있습니다.

하지만 직접 퍼블리싱한 화면을 뿌려주기 위해 showResetPassword 함수를 만들었고 라우트에 해당 함수를 연결시켰습니다.

 

Route::get('password/reset/{token}', 'Auth\BizResetPasswordController@showResetPassword')->middleware('web');

 

또한 기본 라우터만 만들어져있기때문에 추가된 사용자의 비밀번호를 리셋하는 라우터는 추가해줘야 합니다.

먼저 이메일을 보내라는 url 입니다. 실제 우리가 생성한 BizForgotPasswordController 파일에는 sendResetLinkEmail 함수가 없지만 SendsPasswordResetEmails 내의 함수가 호출됩니다.

 

Route::post('password/email', 'Auth\BizForgotPasswordController@sendResetLinkEmail')->middleware('web'); //# 패스워드 초기화 메일 발송

 

마지막으로 변경된 비밀번호를 저장하는 기능을 연결해주는 라우터입니다.

 

Route::post('password/reset', 'Auth\BizResetPasswordController@reset')->middleware('web');

 

마찬가지로 BizResetPasswordController 내에는 reset 함수가 없지만 ResetsPasswords 내의 함수가 호출됩니다.

 

이제 비즈니스 사용자 모델에 비밀번호 재설정 noti 를 보내는 함수를 추가해줍니다.

 

/**
  * Send the password reset notification.
  *
  * @param  string  $token
  * @return void
  */
 public function sendPasswordResetNotification($token)
 {
     $this->notify(new BizResetPassword($token));
 }

 

vendor 내의 PasswordBroker.php 구현부를 보면 사용자의 모델을 가져와서 sendPasswordResetNotification 호출하는 부분을 볼수 있습니다.

 

/**
     * Send a password reset link to a user.
     *
     * @param  array  $credentials
     * @return string
     */
    public function sendResetLink(array $credentials)
    {
        // First we will check to see if we found a user at the given credentials and
        // if we did not we will redirect back to this current URI with a piece of
        // "flash" data in the session to indicate to the developers the errors.
        $user = $this->getUser($credentials);

        if (is_null($user)) {
            return static::INVALID_USER;
        }

        // Once we have the reset token, we are ready to send the message out to this
        // user with a link to reset their password. We will then redirect back to
        // the current URI having nothing set in the session to indicate errors.
        $user->sendPasswordResetNotification(
            $this->tokens->create($user)
        );   // 이 부분이죠!!!

        return static::RESET_LINK_SENT;
    }

 

비즈니스 사용자 모델에서 생성한 BizResetPassword 는 제가 새로 생성한 Notifications 입니다. 기존에는 이미 Notifications/ResetPasswordNotification.php 가 생성되어 있는데 이미 일반사용자에 사용중이라서 새롭게 생성했습니다.

 

php artisan make:notification BizResetPassword

 

Notifications/BizResetPassword.php 파일이 생성되었습니다.

 

class BizResetPassword extends Notification
{
    /**
     * The password reset token.
     *
     * @var string
     */
    public $token;

    /**
     * Create a notification instance.
     *
     * @param  string  $token
     * @return void
     */
    public function __construct($token)
    {
        $this->token = $token;
    }

    /**
     * Get the notification's channels.
     *
     * @param  mixed  $notifiable
     * @return array|string
     */
    public function via($notifiable)
    {
        return ['mail'];
    }

    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        return (new ChangeBizUserPwd($notifiable, $this->token));
    }
}

 

toMail 함수를 수정했습니다. 기본적으로 MailMessage 를 사용해서 보내는데 좀더 커스텀한 메일화면을 위해 메일을 생성해서 변경된 화면을 사용했습니다. 커스텀한 메일 화면은 공식문서에도 잘 나와 있기때문에 생략하도록 하겠습니다.

 

마지막으로 config/auth.php 에 password broker 정보를 추가해줍니다.

 

'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
        ],
        'biz' => [
            'provider' => 'biz',
            'table' => 'password_resets_biz',
            'expire' => 60,
        ],
    ],

 

모든 설정이 끝났습니다.

라라벨이 관례가 많긴 하지만 커스텀한 부분을 잘 고려해서 설계했다는 것을 느낄수 있었습니다.