Laravel - jwt 비밀번호 재설정 이메일 발송 및 변경 > IT 기술백서

IT 기술백서

직접 알아내거나 검색하기 귀찮아서 모아 둔 것

php | Laravel - jwt 비밀번호 재설정 이메일 발송 및 변경

본문

라라벨에서 api 용 인증모듈은 기본적으로 아래의 명령어로 스케폴딩 할 수 있다.

[code]

php artisan breeze:install api 

[/code]

 

하지만 나의 경우 tymon/jwt-auth 를 이용하여 JWT 인증을 사용하기 때문에 위 스케폴딩을 사용할 수가 없었다.

수많은 시행착오끝에 성공하여 기록해 둔다.

 

비밀번호를 분실했을시 재설정 링크 URL을 이메일로 보내고 링크를 클릭시 이메일을 변경할 수 있게 한다.

플로우는 아래와 같다.

 

1) 프론트엔드에서 비밀번호 재설정 클릭

2) 백엔드에서 forgotPassword 메소드를 실행하여 이메일 발송

3) 수신된 이메일에서 버튼 클릭 시 새비밀번호를 입력할 수 있는 프론트엔트 페이지로 연결

4) 새비밀번호 입력 후 백엔드로 전송

5) 백엔드의 resetPasssword 메소드에서 비밀번호 변경 후 성공 통보

 

1. 라우터 추가

/routes/api.php

[code]

// 재설정 링크가 포함된 이메일 보내기

Route::post('/auth/forgot-password', [ JWTAuthController::class, 'forgotPassword' ]); 

// 새비밀번호로 변경

Route::post('/auth/reset_password', [ JWTAuthController::class, 'resetPassword' ]);

});

[/code]

 

2.  컨트롤러에 메소드 정의

[code]

<?php

use Illuminate\Auth\Events\PasswordReset; // 패스워드 변경 이벤트

use Illuminate\Support\Facades\Password; // PasswordBroker 의 파사드

use Illuminate\Validation\ValidationException;

use Illuminate\Support\Facades\Hash;

use Illuminate\Support\Str;

use Illuminate\Validation\Rules;

 

class JWTAuthController extends Controller

{

    // ...

 

    // 재설정 링크가 포함된 이메일 보내기

    public function forgotPassword(Request $request)

    {

        $request->validate([

            'email' => 'required|email'

        ], $request->all());


        $status = Password::sendResetLink(

            $request->only('email')

        );


        if ($status != Password::RESET_LINK_SENT) {

            throw ValidationException::withMessages([

                'email' => [__($status)],

            ]);

        }


        return response()->json(['status' => __($status)]);

    }

    

    // 새비밀번호로 변경

    public function resetPassword(Request $request)

    {

        $request->validate([

            'token' => ['required'],

            'email' => ['required', 'email'],

            'password' => ['required', 'confirmed', Rules\Password::defaults()],

        ]);


        $status = Password::reset(

            $request->only('email', 'password', 'password_confirmation', 'token'),

            function ($user) use ($request) {

                $user->forceFill([

                    'password' => Hash::make($request->password),

                    'remember_token' => Str::random(60),

                ])->save();


                event(new PasswordReset($user));

            }

        );


        if ($status != Password::PASSWORD_RESET) {

            throw ValidationException::withMessages([

                'email' => [__($status)],

            ]);

        }


        return response()->json(['status' => __($status)]);

    }

}

[/code]

 

3. User 모델에 알림 메소드 추가

위 forgotPassword() 메소드에서 Password::sendResetLink() 로 이메일을 발송시 내부적으로 마지막에 User 모델에서 sendPasswordResetNotification($token) 함수를 호출한다.

그래서 User 모델에 해당 메소드를 구현해 주어야 한다.

 

app/Models/User.php

[code]

namespace App\Models;


use Illuminate\Contracts\Auth\MustVerifyEmail;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Foundation\Auth\User as Authenticatable;

use Illuminate\Notifications\Notifiable;

use Laravel\Sanctum\HasApiTokens;

use Tymon\JWTAuth\Contracts\JWTSubject;

use Illuminate\Auth\Notifications\VerifyEmail;

use Illuminate\Auth\Notifications\ResetPassword;


class User extends Authenticatable implements JWTSubject, MustVerifyEmail

{

    use HasApiTokens, HasFactory, Notifiable;

 

    // ....

 

 

    public function sendPasswordResetNotification($token)

    {

        $this->notify(new ResetPassword($token));  // 여기서 ResetPassword 알림을 보내면 이메일이 전송된다.

    }

}

[/code]

 

4. 재설정 링크 URL 변경하기

3번까지 하고 forgotPassword() 를 실행하면 링크 URL이 백엔드용 URL로 전송된다.

우리의 경우는 프론트엔드의 비밀번호변경 페이지로 가야하기 때문에 URL을 변경해줘야 한다.

 

app/Providers/AuthServiceProvider.php

[code]

<?php


namespace App\Providers;


use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

use Illuminate\Auth\Notifications\ResetPassword;


class AuthServiceProvider extends ServiceProvider

{

    // ...

    public function boot()

    {

        $this->registerPolicies();


        // ResetPassword 알림 클래스의 비밀번호재설정 URL 생성 재정의

        ResetPassword::createUrlUsing(function ($notifiable, $token) {

            return config('app.frontend_url')

                ."/users/password-reset?token={$token}&email={$notifiable->getEmailForPasswordReset()}";

        });

    }

}

[/code]

 

5. 환경설정 파일에 프론트엔드 URL을 추가해준다. 

/.env

[code]

FRONTEND_URL=http://example.com

[/code]

 

/config/app.php

[code]

'frontend_url' => env('FRONTEND_URL', 'http://localhost:3000'),

[/code]

 

6. 프론트 엔드에 비밀번호 재설정 폼 제작

: 여기서는 nuxt 라 가정하고 아래의 주소에 페이지를 작성한다.

/pages/users/password-reset.vue

 

새 비밀번호 전송 구문 예

[code language-javascript]

this.$axios

  .post('http://example.com/api/v1/auth/reset-password', {

    token: this.token,

    email: this.email,

    password: this.password,

    password_confirmation: this.password_confirmation,

  })

  .then(() => {

    this.$alert('비밀번호가 변경되었습니다').then(() => {

      this.$router.push('/')

    })

  })

  .catch((err) => {

    console.log(err)

  })

[/code]

 

댓글 0개

등록된 댓글이 없습니다.

Menu