Skip to content

Commit

Permalink
refactor: password reset support
Browse files Browse the repository at this point in the history
Also migrate necessary controllers
  • Loading branch information
Luke committed Aug 20, 2020
1 parent e5fa41e commit 06bbca4
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/app/Auth/Concerns/CanResetPassword.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public function getEmailForPasswordReset()
*/
public function sendPasswordResetNotification($token)
{
$this->user->notify(new ResetPasswordNotification($token));
$this->notify(new ResetPasswordNotification($token));
}
}
11 changes: 5 additions & 6 deletions src/app/Auth/Concerns/MustVerifyEmail.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

namespace Bluewing\Auth\Concerns;

use Carbon\Carbon;
use Bluewing\Eloquent\Model;
use Illuminate\Auth\Notifications\VerifyEmail;

/**
* Trait BluewingMustVerifyEmail
*
* @property string email - This property exists on all models that this trait traits.
* @property Carbon emailVerifiedAt - This property exists on all models that this trait traits.
* @property Model user - The `User` model that is related to the model that traits the `MustVerifyEmail` functionality.
*
* @package Bluewing
*
Expand All @@ -28,7 +27,7 @@ trait MustVerifyEmail {
*/
public function hasVerifiedEmail()
{
return ! is_null($this->emailVerifiedAt);
return ! is_null($this->user->emailVerifiedAt);
}

/**
Expand All @@ -38,7 +37,7 @@ public function hasVerifiedEmail()
*/
public function markEmailAsVerified()
{
return $this->forceFill([
return $this->user->forceFill([
'emailVerifiedAt' => $this->freshTimestamp(),
])->save();
}
Expand All @@ -60,6 +59,6 @@ public function sendEmailVerificationNotification()
*/
public function getEmailForVerification()
{
return $this->email;
return $this->user->email;
}
}
97 changes: 97 additions & 0 deletions src/app/Auth/Concerns/ResetsPasswords.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php


namespace Bluewing\Auth\Concerns;

use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Contracts\Auth\CanResetPassword;
use Illuminate\Foundation\Auth\ResetsPasswords as IlluminateResetsPasswords;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

/**
* Trait ResetsPasswords
*
* Overrides the default `ResetsPasswords` trait to provide custom functionality for sending out responses.
*
* @package Bluewing\Auth\Concerns
*/
trait ResetsPasswords
{
use IlluminateResetsPasswords;

/**
* Override the default reset password response to return `200 OK` always, if the password was
* successfully reset for the user, with user details in the response body.
*
* @param Request $request - The `Request` that is being processed.
* @param $response - The response message that would otherwise be sent.
*
* @return JsonResponse -
*/
protected function sendResetResponse(Request $request, $response)
{
return response()->json($this->guard()->user());
}

/**
* Set the user's password. This overrides the `setUserPassword` method in the `ResetsPasswords` trait to remove
* the hashing mechanism, as this is performed automatically in the `User` class mutator for this property.
*
* @param CanResetPassword $member
* @param string $password
* @return void
*/
protected function setUserPassword($member, $password)
{
$member->user->password = $password;
}

/**
* Override the credentials needed to perform a password reset. We do not require a password confirmation to
* process the request.
*
* @param Request $request
* @return array
*/
protected function credentials(Request $request)
{
return $request->only(
'password', 'email', 'token'
);
}

/**
* Override the password reset rules to remove the need for a password confirmation.
*
* @return array
*/
protected function rules()
{
return [
'token' => 'required',
'email' => 'required|email',
'password' => 'required|min:6',
];
}

/**
* Reset the given user's password. This removes the creation of a `rememberToken` property that is not used, and
* replaces the `guard()->login()` call with a `guard()->setUser()` call. Additionally, ensure we are saving the
* `User`, and not the `Member`, as the password is not stored on the `Member` instance.
*
* @param CanResetPassword $member
* @param string $password
*
* @return void
*/
protected function resetPassword($member, $password)
{
$this->setUserPassword($member, $password);
$member->user->save();

event(new PasswordReset($member));

$this->guard()->setUser($member);
}
}
10 changes: 7 additions & 3 deletions src/app/Auth/Member.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;

use Bluewing\Auth\Concerns\Authenticatable as BluewingAuthenticatable;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Bluewing\Auth\Concerns\CanResetPassword as BluewingCanResetPassword;
use Bluewing\Auth\Concerns\MustVerifyEmail as BluewingMustVerifyEmail;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;

class Member extends BluewingPivot implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
class Member extends BluewingPivot implements
AuthenticatableContract, AuthorizableContract,
CanResetPasswordContract, MustVerifyEmailContract
{
use BluewingAuthenticatable, Authorizable, BluewingCanResetPassword, BluewingMustVerifyEmail;
use BluewingAuthenticatable, BluewingCanResetPassword, BluewingMustVerifyEmail, Authorizable, Notifiable;
}
41 changes: 41 additions & 0 deletions src/app/Http/Controllers/ForgotPasswordController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Bluewing\Http\Controllers;

use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\JsonResponse;
use Illuminate\Routing\Controller;
use Illuminate\Http\Request;

class ForgotPasswordController extends Controller
{
use SendsPasswordResetEmails;

/**
* This provides an invokable shortcut to the `sendResetLinkEmail` method contained in the
* `SendsPasswordResetEmails` trait.
*
* @param Request $request -
*
* @return JsonResponse -
*/
public function __invoke(Request $request)
{
return $this->sendResetLinkEmail($request);
}

/**
* Override the default reset link response to return `204 No Content` always, if the reset link was successfully
* sent.
*
* @param Request $request
* @param $response
*
* @return JsonResponse
*/
protected function sendResetLinkResponse(Request $request, $response)
{
return response()->json(null, 204);
}
}

36 changes: 36 additions & 0 deletions src/app/Http/Controllers/ResetPasswordController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Bluewing\Http\Controllers;

use Bluewing\Auth\Concerns\ResetsPasswords;
use Bluewing\Http\Middleware\AppendTokensToResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class ResetPasswordController extends Controller
{
use ResetsPasswords;

/**
* Constructor for `ResetPasswordController`.
*
* Ensures that JWT and refresh tokens are appropriately appended to the headers of each successful reset
* password response. This is necessary because once the request is completed, the user is considered logged in.
*/
public function __construct()
{
$this->middleware(AppendTokensToResponse::class);
}

/**
* This provides an invokable shortcut to the `reset` method contained in the `ResetsPasswords` trait.
*
* @param Request $request -
*
* @return JsonResponse -
*/
public function __invoke(Request $request)
{
return $this->reset($request);
}
}

0 comments on commit 06bbca4

Please sign in to comment.