From 681e3562d5244487fcc3c0902c1040f7bd54df47 Mon Sep 17 00:00:00 2001 From: Lupacescu Eduard Date: Mon, 30 Mar 2020 09:40:37 +0300 Subject: [PATCH 1/4] wip --- config/config.php | 4 +- src/Commands/PolicyCommand.php | 2 +- src/Contracts/Sanctumable.php | 7 + src/Controllers/AuthController.php | 42 +++ src/Exceptions/AirlockUserException.php | 12 - .../AuthenticatableUserException.php | 6 + src/Exceptions/SanctumUserException.php | 16 ++ src/Notifications/VerifyEmail.php | 58 ++++ src/Repositories/Crudable.php | 8 +- src/Services/AuthService.php | 248 ++---------------- src/Services/ForgotPasswordService.php | 20 ++ src/Services/LoginService.php | 20 ++ src/Services/LogoutService.php | 33 +++ src/Services/PassportService.php | 91 +++++++ src/Services/RegisterService.php | 84 ++++++ src/Services/ResetPasswordService.php | 20 ++ tests/AuthServiceLoginTest.php | 9 +- 17 files changed, 435 insertions(+), 245 deletions(-) create mode 100644 src/Contracts/Sanctumable.php create mode 100644 src/Controllers/AuthController.php delete mode 100644 src/Exceptions/AirlockUserException.php create mode 100644 src/Exceptions/SanctumUserException.php create mode 100644 src/Notifications/VerifyEmail.php create mode 100644 src/Services/ForgotPasswordService.php create mode 100644 src/Services/LoginService.php create mode 100644 src/Services/LogoutService.php create mode 100644 src/Services/PassportService.php create mode 100644 src/Services/RegisterService.php create mode 100644 src/Services/ResetPasswordService.php diff --git a/config/config.php b/config/config.php index 60c24a033..1b80ff1ae 100644 --- a/config/config.php +++ b/config/config.php @@ -25,10 +25,10 @@ | this will be used for the verification of the authenticatable model and provide the | authorizable functionality | - | Supported: "passport", "airlock" + | Supported: "passport", "sanctum" */ - 'provider' => 'airlock', + 'provider' => 'sanctum', ], /* diff --git a/src/Commands/PolicyCommand.php b/src/Commands/PolicyCommand.php index 4678a8a0c..5c8b59b0c 100644 --- a/src/Commands/PolicyCommand.php +++ b/src/Commands/PolicyCommand.php @@ -110,7 +110,7 @@ protected function getStub() */ protected function getDefaultNamespace($rootNamespace) { - return $rootNamespace.'\Restify'; + return $rootNamespace.'\Policies'; } /** diff --git a/src/Contracts/Sanctumable.php b/src/Contracts/Sanctumable.php new file mode 100644 index 000000000..9ec0ebf3c --- /dev/null +++ b/src/Contracts/Sanctumable.php @@ -0,0 +1,7 @@ +authService = $authService; + } + + public function login(Request $request) + { + return $this->authService->login($request); + } + + public function register(Request $request) + { + return $this->authService->register($request); + } + + public function verify(Request $request) + { + return $this->authService->verify($request); + } + + public function forgotPassword(Request $request) + { + return $this->authService->forgotPassword($request); + } + + public function resetPassword(Request $request) + { + return $this->authService->resetPassword($request); + } +} diff --git a/src/Exceptions/AirlockUserException.php b/src/Exceptions/AirlockUserException.php deleted file mode 100644 index 7160ef950..000000000 --- a/src/Exceptions/AirlockUserException.php +++ /dev/null @@ -1,12 +0,0 @@ - - */ -class AirlockUserException extends Exception -{ -} diff --git a/src/Exceptions/AuthenticatableUserException.php b/src/Exceptions/AuthenticatableUserException.php index e2222ae2a..5f61fde0c 100644 --- a/src/Exceptions/AuthenticatableUserException.php +++ b/src/Exceptions/AuthenticatableUserException.php @@ -9,4 +9,10 @@ */ class AuthenticatableUserException extends Exception { + public static function wrongInstance(): self + { + $message = __("Repository model should be an instance of \Illuminate\Contracts\Auth\Authenticatable"); + + return new static($message); + } } diff --git a/src/Exceptions/SanctumUserException.php b/src/Exceptions/SanctumUserException.php new file mode 100644 index 000000000..a8263d71b --- /dev/null +++ b/src/Exceptions/SanctumUserException.php @@ -0,0 +1,16 @@ + + */ +class SanctumUserException extends Exception +{ + public static function wrongConfiguration() + { + return new static("Auth provider should be [sanctum] in the configuration [restify.auth.provider]."); + } +} diff --git a/src/Notifications/VerifyEmail.php b/src/Notifications/VerifyEmail.php new file mode 100644 index 000000000..a3397258b --- /dev/null +++ b/src/Notifications/VerifyEmail.php @@ -0,0 +1,58 @@ +verificationUrl($notifiable); + + if (static::$toMailCallback) { + return call_user_func(static::$toMailCallback, $notifiable, $verificationUrl); + } + + return (new MailMessage) + ->subject(Lang::get('Verify Email Address')) + ->line(Lang::get('Please click the button below to verify your email address.')) + ->action(Lang::get('Verify Email Address'), $verificationUrl) + ->line(Lang::get('If you did not create an account, no further action is required.')); + } + + /** + * Get the verification URL for the given notifiable. + * + * @param mixed $notifiable + * @return string + */ + protected function verificationUrl($notifiable) + { + return URL::temporarySignedRoute( + 'restify.verification.verify', + Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)), + [ + 'id' => $notifiable->getKey(), + 'hash' => sha1($notifiable->getEmailForVerification()), + ] + ); + } + + /** + * Set a callback that should be used when building the notification mail message. + * + * @param \Closure $callback + * @return void + */ + public static function toMailUsing($callback) + { + static::$toMailCallback = $callback; + } +} diff --git a/src/Repositories/Crudable.php b/src/Repositories/Crudable.php index c45d79a64..1a4281c22 100644 --- a/src/Repositories/Crudable.php +++ b/src/Repositories/Crudable.php @@ -12,6 +12,7 @@ use Binaryk\LaravelRestify\Restify; use Binaryk\LaravelRestify\Services\Search\SearchService; use Illuminate\Auth\Access\AuthorizationException; +use Illuminate\Database\Eloquent\Model; use Illuminate\Http\JsonResponse; use Illuminate\Pagination\AbstractPaginator; use Illuminate\Support\Collection; @@ -104,7 +105,7 @@ public function store(RestifyRequest $request) $this->resource = static::storePlain($request->toArray()); - static::stored($this->resource); + static::stored($this->resource, $request); return $this->response('', RestResponse::REST_RESPONSE_CREATED_CODE) ->model($this->resource) @@ -324,9 +325,10 @@ public static function destroyPlain($key) } /** - * @param $model + * @param Model $model + * @param RestifyRequest $request */ - public static function stored($model) + public static function stored(Model $model, RestifyRequest $request) { // } diff --git a/src/Services/AuthService.php b/src/Services/AuthService.php index dfed14ad9..1f4c0f9cd 100644 --- a/src/Services/AuthService.php +++ b/src/Services/AuthService.php @@ -2,26 +2,12 @@ namespace Binaryk\LaravelRestify\Services; -use Binaryk\LaravelRestify\Contracts\Airlockable; use Binaryk\LaravelRestify\Contracts\Passportable; -use Binaryk\LaravelRestify\Events\UserLoggedIn; -use Binaryk\LaravelRestify\Events\UserLogout; -use Binaryk\LaravelRestify\Exceptions\AirlockUserException; -use Binaryk\LaravelRestify\Exceptions\AuthenticatableUserException; -use Binaryk\LaravelRestify\Exceptions\CredentialsDoesntMatch; +use Binaryk\LaravelRestify\Contracts\Sanctumable; use Binaryk\LaravelRestify\Exceptions\Eloquent\EntityNotFoundException; use Binaryk\LaravelRestify\Exceptions\PassportUserException; -use Binaryk\LaravelRestify\Exceptions\PasswordResetException; -use Binaryk\LaravelRestify\Exceptions\PasswordResetInvalidTokenException; -use Binaryk\LaravelRestify\Exceptions\UnverifiedUser; -use Binaryk\LaravelRestify\Http\Requests\ResetPasswordRequest; -use Binaryk\LaravelRestify\Http\Requests\RestifyPasswordEmailRequest; -use Binaryk\LaravelRestify\Http\Requests\RestifyRegisterRequest; -use Binaryk\LaravelRestify\Tests\Fixtures\User; -use Closure; +use Binaryk\LaravelRestify\Exceptions\SanctumUserException; use Illuminate\Auth\Access\AuthorizationException; -use Illuminate\Auth\Events\PasswordReset; -use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Verified; use Illuminate\Container\Container; use Illuminate\Contracts\Auth\Authenticatable; @@ -29,13 +15,9 @@ use Illuminate\Contracts\Auth\PasswordBroker; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Database\Eloquent\Model; -use Illuminate\Support\Facades\Auth; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Password; -use Illuminate\Support\Facades\Validator; -use Illuminate\Support\Str; -use Illuminate\Validation\ValidationException; use ReflectionException; /** @@ -43,88 +25,27 @@ */ class AuthService extends RestifyService { - /** - * @var string - */ - public static $registerFormRequest = RestifyRegisterRequest::class; - - /** - * The callback that should be used to create the registered user. - * - * @var Closure|null - */ - public static $creating; - - /** - * @param array $credentials - * @return string|null - * @throws CredentialsDoesntMatch - * @throws UnverifiedUser - * @throws PassportUserException - * @throws AirlockUserException - */ - public function login(array $credentials = []) + public function login(Request $request) { - $token = null; - - if (Auth::attempt($credentials) === false) { - throw new CredentialsDoesntMatch("Credentials doesn't match"); + if (config('restify.auth.provider') !== 'sanctum') { + throw SanctumUserException::wrongConfiguration(); } - /** - * @var Authenticatable|Passportable|Airlockable - */ - $user = Auth::user(); - - if ($user instanceof MustVerifyEmail && $user->hasVerifiedEmail() === false) { - throw new UnverifiedUser('The email is not verified'); - } - - $this->validateUserModel($user); - - if (method_exists($user, 'createToken')) { - $token = $user->createToken('Login')->accessToken; - event(new UserLoggedIn($user)); - } - - return $token; + return LoginService::make($request); } - /** - * @param array $payload - * @return \Illuminate\Database\Eloquent\Builder|Model|mixed - * @throws AuthenticatableUserException - * @throws EntityNotFoundException - * @throws PassportUserException - * @throws ValidationException - * @throws BindingResolutionException - * @throws AirlockUserException - */ - public function register(array $payload) + public function register(Request $request) { - $this->validateRegister($payload); - - $builder = $this->userQuery(); - - if (false === $builder instanceof Authenticatable) { - throw new AuthenticatableUserException(__("Repository model should be an instance of \Illuminate\Contracts\Auth\Authenticatable")); - } - - /** - * @var Authenticatable - */ - $user = $builder->query()->create(array_merge($payload, [ - 'password' => Hash::make(data_get($payload, 'password')), - ])); - - if ($user instanceof Authenticatable) { - event(new Registered($user)); - } + return RegisterService::make($request); + } - return $user; + public function forgotPassword(Request $request) + { + return ForgotPasswordService::make($request); } - /** + + /* * @param $id * @param null $hash * @return Builder|Builder[]|\Illuminate\Database\Eloquent\Collection|Model|null @@ -139,7 +60,7 @@ public function verify($id, $hash = null) */ $user = $this->userQuery()->query()->find($id); - if ($user instanceof Passportable && ! hash_equals((string) $hash, sha1($user->getEmail()))) { + if ($user instanceof Sanctumable && !hash_equals((string)$hash, sha1($user->getEmailForVerification()))) { throw new AuthorizationException('Invalid hash'); } @@ -150,63 +71,9 @@ public function verify($id, $hash = null) return $user; } - /** - * @param $email - * @return string - * @throws EntityNotFoundException - * @throws PasswordResetInvalidTokenException - * @throws ValidationException - * @throws PasswordResetException - */ - public function sendResetPasswordLinkEmail($email) + public function resetPassword(Request $request) { - $validator = Validator::make(compact('email'), (new RestifyPasswordEmailRequest)->rules(), (new RestifyPasswordEmailRequest)->messages()); - if ($validator->fails()) { - // this is manually thrown for readability - throw new ValidationException($validator); - } - // We will send the password reset link to this user. Once we have attempted - // to send the link, we will examine the response then see the message we - // need to show to the user. Finally, we'll send out a proper response. - $response = $this->broker()->sendResetLink(compact('email')); - $this->resolveBrokerResponse($response, PasswordBroker::RESET_LINK_SENT, PasswordBroker::PASSWORD_RESET); - - return $response; - } - - /** - * @param array $credentials - * @return JsonResponse - * @throws PasswordResetInvalidTokenException - * @throws ValidationException - * @throws EntityNotFoundException - * @throws PasswordResetException - */ - public function resetPassword(array $credentials = []) - { - $validator = Validator::make($credentials, (new ResetPasswordRequest())->rules(), (new ResetPasswordRequest())->messages()); - if ($validator->fails()) { - // this is manually thrown for readability - throw new ValidationException($validator); - } - - // Here we will attempt to reset the user's password. If it is successful we - // will update the password on an actual user model and persist it to the - // database. Otherwise we will parse the error and return the response. - $response = $this->broker()->reset( - $credentials, function ($user, $password) { - $user->password = Hash::make($password); - - $user->setRememberToken(Str::random(60)); - - $user->save(); - - event(new PasswordReset($user)); - }); - - $this->resolveBrokerResponse($response, PasswordBroker::PASSWORD_RESET); - - return $response; + return ResetPasswordService::make($request); } /** @@ -220,10 +87,10 @@ public function broker() /** * Returns query for User model and validate if it exists. * - * @throws EntityNotFoundException - * @throws PassportUserException - * @throws AirlockUserException * @return Model + * @throws PassportUserException + * @throws SanctumUserException + * @throws EntityNotFoundException */ public function userQuery() { @@ -244,7 +111,7 @@ public function userQuery() /** * @param $userInstance * @throws PassportUserException - * @throws AirlockUserException + * @throws SanctumUserException */ public function validateUserModel($userInstance) { @@ -252,78 +119,13 @@ public function validateUserModel($userInstance) throw new PassportUserException(__("User is not implementing Binaryk\LaravelRestify\Contracts\Passportable contract. User can use 'Laravel\Passport\HasApiTokens' trait")); } - if (config('restify.auth.provider') === 'airlock' && false === $userInstance instanceof Airlockable) { - throw new AirlockUserException(__("User is not implementing Binaryk\LaravelRestify\Contracts\Airlockable contract. User should use 'Laravel\Airlock\HasApiTokens' trait to provide")); - } - } - - /** - * @param $response - * @param null $case - * @throws EntityNotFoundException - * @throws PasswordResetException - * @throws PasswordResetInvalidTokenException - */ - protected function resolveBrokerResponse($response, $case = null) - { - if ($response === PasswordBroker::INVALID_TOKEN) { - throw new PasswordResetInvalidTokenException(__('Invalid token.')); - } - - if ($response === PasswordBroker::INVALID_USER) { - throw new EntityNotFoundException(__("User with provided email doesn't exists.")); - } - if ($case && $response !== $case) { - throw new PasswordResetException($response); + if (config('restify.auth.provider') === 'sanctum' && false === $userInstance instanceof Sanctumable) { + throw new SanctumUserException(__("User is not implementing Binaryk\LaravelRestify\Contracts\Sanctumable contract. User should use 'Laravel\Sanctum\HasApiTokens' trait to provide")); } } - /** - * @param array $payload - * @return bool - * @throws ValidationException - * @throws BindingResolutionException - */ - public function validateRegister(array $payload) - { - try { - if (class_exists(static::$registerFormRequest) && (new \ReflectionClass(static::$registerFormRequest))->isInstantiable()) { - $validator = Validator::make($payload, (new static::$registerFormRequest)->rules(), (new static::$registerFormRequest)->messages()); - if ($validator->fails()) { - throw new ValidationException($validator); - } - } - } catch (ReflectionException $e) { - $concrete = static::$registerFormRequest; - throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); - } - - return true; - } - - /** - * Revoke tokens for user. - * - * @throws AuthenticatableUserException - */ public function logout() { - /** - * @var User - */ - $user = Auth::user(); - if ($user instanceof Authenticatable) { - if ($user instanceof Passportable) { - $user->tokens()->get()->each->revoke(); - event(new UserLogout($user)); - } - - if ($user instanceof Airlockable) { - $user->tokens->each->delete(); - event(new UserLogout($user)); - } - } else { - throw new AuthenticatableUserException(__('User is not authenticated.')); - } + return LogoutService::make(); } } diff --git a/src/Services/ForgotPasswordService.php b/src/Services/ForgotPasswordService.php new file mode 100644 index 000000000..930e77a55 --- /dev/null +++ b/src/Services/ForgotPasswordService.php @@ -0,0 +1,20 @@ + + */ +class ForgotPasswordService +{ + use SendsPasswordResetEmails; + + public static function make(Request $request) + { + return resolve(static::class)->sendResetLinkEmail($request); + } +} diff --git a/src/Services/LoginService.php b/src/Services/LoginService.php new file mode 100644 index 000000000..e9a46872a --- /dev/null +++ b/src/Services/LoginService.php @@ -0,0 +1,20 @@ + + */ +class LoginService +{ + use AuthenticatesUsers; + + public static function make(Request $request) + { + return resolve(static::class)->login($request); + } +} diff --git a/src/Services/LogoutService.php b/src/Services/LogoutService.php new file mode 100644 index 000000000..d383efbfb --- /dev/null +++ b/src/Services/LogoutService.php @@ -0,0 +1,33 @@ + + */ +class LogoutService +{ + use AuthenticatesUsers; + + public static function make(Request $request) + { + /** + * @var User + */ + $user = Auth::user(); + + if ($user instanceof Authenticatable) { + return resolve(static::class)->logout($request); + } else { + throw new AuthenticatableUserException(__('User is not authenticated.')); + } + } +} diff --git a/src/Services/PassportService.php b/src/Services/PassportService.php new file mode 100644 index 000000000..e3360dadc --- /dev/null +++ b/src/Services/PassportService.php @@ -0,0 +1,91 @@ + + */ +class PassportService extends RestifyService +{ + /** + * Create user token based on credentials + * + * @param array $credentials + * @return string|null + * @throws CredentialsDoesntMatch + * @throws PassportUserException + * @throws UnverifiedUser + */ + public function createToken(array $credentials = []) + { + $token = null; + + if (Auth::attempt($credentials) === false) { + throw new CredentialsDoesntMatch("Credentials doesn't match"); + } + + /** + * @var Authenticatable|Passportable|Sanctumable + */ + $user = Auth::user(); + + if ($user instanceof MustVerifyEmail && $user->hasVerifiedEmail() === false) { + throw new UnverifiedUser('The email is not verified'); + } + + $this->validateUserModel($user); + + if (method_exists($user, 'createToken')) { + $token = $user->createToken('Login'); + event(new UserLoggedIn($user)); + } + + return $token; + } + + /** + * @param $userInstance + * @throws PassportUserException + */ + public function validateUserModel($userInstance) + { + if (config('restify.auth.provider') === 'passport' && false === $userInstance instanceof Passportable) { + throw new PassportUserException(__("User is not implementing Binaryk\LaravelRestify\Contracts\Passportable contract. User can use 'Laravel\Passport\HasApiTokens' trait")); + } + } + + /** + * Revoke tokens for user. + * + * @throws AuthenticatableUserException + */ + public function logout() + { + /** + * @var User + */ + $user = Auth::user(); + + if ($user instanceof Authenticatable) { + if ($user instanceof Passportable) { + $user->tokens()->get()->each->revoke(); + event(new UserLogout($user)); + } + } else { + throw new AuthenticatableUserException(__('User is not authenticated.')); + } + } +} diff --git a/src/Services/RegisterService.php b/src/Services/RegisterService.php new file mode 100644 index 000000000..482993dec --- /dev/null +++ b/src/Services/RegisterService.php @@ -0,0 +1,84 @@ + + */ +class RegisterService +{ + + /** + * The callback that should be used to create the registered user. + * + * @var Closure|null + */ + public static Closure $creating; + + public static $registerFormRequest = RestifyRegisterRequest::class; + + public function register(Request $request) + { + $payload = $request->all(); + + $this->validateRegister($payload); + + $builder = $this->userQuery(); + + if (false === $builder instanceof Authenticatable) { + throw AuthenticatableUserException::wrongInstance(); + } + + $userData = array_merge($payload, [ + 'password' => Hash::make(data_get($payload, 'password')), + ]); + + if (is_callable(static::$creating)) { + $user = call_user_func(static::$creating, $userData); + } else { + $user = $builder->query()->create($userData); + } + + if ($user instanceof Authenticatable) { + event(new Registered($user)); + } + + return $user; + } + + public static function make(Request $request) + { + return resolve(static::class)->register($request); + } + + public function validateRegister(array $payload) + { + try { + if (class_exists(static::$registerFormRequest) && (new \ReflectionClass(static::$registerFormRequest))->isInstantiable()) { + $validator = Validator::make($payload, (new static::$registerFormRequest)->rules(), (new static::$registerFormRequest)->messages()); + if ($validator->fails()) { + throw new ValidationException($validator); + } + } + } catch (ReflectionException $e) { + $concrete = static::$registerFormRequest; + throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); + } + + return true; + } + +} diff --git a/src/Services/ResetPasswordService.php b/src/Services/ResetPasswordService.php new file mode 100644 index 000000000..4eba3d863 --- /dev/null +++ b/src/Services/ResetPasswordService.php @@ -0,0 +1,20 @@ + + */ +class ResetPasswordService +{ + use ResetsPasswords; + + public static function make(Request $request) + { + return resolve(static::class)->reset($request); + } +} diff --git a/tests/AuthServiceLoginTest.php b/tests/AuthServiceLoginTest.php index 820d94747..8567d068d 100644 --- a/tests/AuthServiceLoginTest.php +++ b/tests/AuthServiceLoginTest.php @@ -5,7 +5,7 @@ use Binaryk\LaravelRestify\Contracts\Passportable; use Binaryk\LaravelRestify\Events\UserLoggedIn; use Binaryk\LaravelRestify\Events\UserLogout; -use Binaryk\LaravelRestify\Exceptions\AirlockUserException; +use Binaryk\LaravelRestify\Exceptions\SanctumUserException; use Binaryk\LaravelRestify\Exceptions\AuthenticatableUserException; use Binaryk\LaravelRestify\Exceptions\CredentialsDoesntMatch; use Binaryk\LaravelRestify\Exceptions\PassportUserException; @@ -96,10 +96,11 @@ public function test_login_user_did_not_user_passport_trait_or_not_implement_pas $this->authService->login(); } - public function test_login_user_did_not_user_passport_trait_or_not_implement_airlockable() + public function test_login_user_did_not_user_passport_trait_or_not_implement_sanctumable() { - $this->app['config']->set('restify.auth.provider', 'airlock'); - $this->expectException(AirlockUserException::class); + $this->app['config']->set('restify.auth.provider', 'sanctum'); + $this->expectException(SanctumUserException::class); + $userMustVerify = (new class extends User implements MustVerifyEmail { use \Illuminate\Auth\MustVerifyEmail; }); From af6ea7b9c8539ba42df278defd3e9183cbdc2c65 Mon Sep 17 00:00:00 2001 From: Lupacescu Eduard Date: Mon, 30 Mar 2020 09:41:01 +0300 Subject: [PATCH 2/4] Apply fixes from StyleCI (#145) --- src/Controllers/AuthController.php | 1 - src/Exceptions/SanctumUserException.php | 2 +- src/Services/AuthService.php | 3 +-- src/Services/ForgotPasswordService.php | 1 - src/Services/LoginService.php | 1 - src/Services/LogoutService.php | 1 - src/Services/PassportService.php | 2 +- src/Services/RegisterService.php | 3 --- src/Services/ResetPasswordService.php | 1 - tests/AuthServiceLoginTest.php | 2 +- 10 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index b8e3304c3..47831d3b7 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -11,7 +11,6 @@ class AuthController extends RestController public function __construct(AuthService $authService) { - $this->authService = $authService; } diff --git a/src/Exceptions/SanctumUserException.php b/src/Exceptions/SanctumUserException.php index a8263d71b..ac97e7280 100644 --- a/src/Exceptions/SanctumUserException.php +++ b/src/Exceptions/SanctumUserException.php @@ -11,6 +11,6 @@ class SanctumUserException extends Exception { public static function wrongConfiguration() { - return new static("Auth provider should be [sanctum] in the configuration [restify.auth.provider]."); + return new static('Auth provider should be [sanctum] in the configuration [restify.auth.provider].'); } } diff --git a/src/Services/AuthService.php b/src/Services/AuthService.php index 1f4c0f9cd..e74819e52 100644 --- a/src/Services/AuthService.php +++ b/src/Services/AuthService.php @@ -44,7 +44,6 @@ public function forgotPassword(Request $request) return ForgotPasswordService::make($request); } - /* * @param $id * @param null $hash @@ -60,7 +59,7 @@ public function verify($id, $hash = null) */ $user = $this->userQuery()->query()->find($id); - if ($user instanceof Sanctumable && !hash_equals((string)$hash, sha1($user->getEmailForVerification()))) { + if ($user instanceof Sanctumable && ! hash_equals((string) $hash, sha1($user->getEmailForVerification()))) { throw new AuthorizationException('Invalid hash'); } diff --git a/src/Services/ForgotPasswordService.php b/src/Services/ForgotPasswordService.php index 930e77a55..a0c96245c 100644 --- a/src/Services/ForgotPasswordService.php +++ b/src/Services/ForgotPasswordService.php @@ -6,7 +6,6 @@ use Illuminate\Http\Request; /** - * @package Binaryk\LaravelRestify\Services; * @author Eduard Lupacescu */ class ForgotPasswordService diff --git a/src/Services/LoginService.php b/src/Services/LoginService.php index e9a46872a..9966b6557 100644 --- a/src/Services/LoginService.php +++ b/src/Services/LoginService.php @@ -6,7 +6,6 @@ use Illuminate\Http\Request; /** - * @package Binaryk\LaravelRestify\Services; * @author Eduard Lupacescu */ class LoginService diff --git a/src/Services/LogoutService.php b/src/Services/LogoutService.php index d383efbfb..72b36a8bb 100644 --- a/src/Services/LogoutService.php +++ b/src/Services/LogoutService.php @@ -10,7 +10,6 @@ use Illuminate\Support\Facades\Auth; /** - * @package Binaryk\LaravelRestify\Services; * @author Eduard Lupacescu */ class LogoutService diff --git a/src/Services/PassportService.php b/src/Services/PassportService.php index e3360dadc..dbe2fd5b6 100644 --- a/src/Services/PassportService.php +++ b/src/Services/PassportService.php @@ -21,7 +21,7 @@ class PassportService extends RestifyService { /** - * Create user token based on credentials + * Create user token based on credentials. * * @param array $credentials * @return string|null diff --git a/src/Services/RegisterService.php b/src/Services/RegisterService.php index 482993dec..3647075c7 100644 --- a/src/Services/RegisterService.php +++ b/src/Services/RegisterService.php @@ -15,12 +15,10 @@ use ReflectionException; /** - * @package Binaryk\LaravelRestify\Services; * @author Eduard Lupacescu */ class RegisterService { - /** * The callback that should be used to create the registered user. * @@ -80,5 +78,4 @@ public function validateRegister(array $payload) return true; } - } diff --git a/src/Services/ResetPasswordService.php b/src/Services/ResetPasswordService.php index 4eba3d863..2b3f8c13a 100644 --- a/src/Services/ResetPasswordService.php +++ b/src/Services/ResetPasswordService.php @@ -6,7 +6,6 @@ use Illuminate\Http\Request; /** - * @package Binaryk\LaravelRestify\Services; * @author Eduard Lupacescu */ class ResetPasswordService diff --git a/tests/AuthServiceLoginTest.php b/tests/AuthServiceLoginTest.php index 8567d068d..8fb340655 100644 --- a/tests/AuthServiceLoginTest.php +++ b/tests/AuthServiceLoginTest.php @@ -5,10 +5,10 @@ use Binaryk\LaravelRestify\Contracts\Passportable; use Binaryk\LaravelRestify\Events\UserLoggedIn; use Binaryk\LaravelRestify\Events\UserLogout; -use Binaryk\LaravelRestify\Exceptions\SanctumUserException; use Binaryk\LaravelRestify\Exceptions\AuthenticatableUserException; use Binaryk\LaravelRestify\Exceptions\CredentialsDoesntMatch; use Binaryk\LaravelRestify\Exceptions\PassportUserException; +use Binaryk\LaravelRestify\Exceptions\SanctumUserException; use Binaryk\LaravelRestify\Exceptions\UnverifiedUser; use Binaryk\LaravelRestify\Services\AuthService; use Binaryk\LaravelRestify\Tests\Fixtures\SimpleUser as User; From fb651567013fece48b97f36a9aada20dd296d592 Mon Sep 17 00:00:00 2001 From: Eduard Lupacescu Date: Sun, 10 May 2020 17:50:09 +0300 Subject: [PATCH 3/4] Refactoring authentication service --- composer.json | 3 +- config/config.php | 14 ++ src/Commands/CheckPassport.php | 2 +- src/Services/AuthService.php | 8 +- src/Services/ForgotPasswordService.php | 8 + src/Services/LoginService.php | 29 +++ src/Services/RegisterService.php | 21 +- src/Services/ResetPasswordService.php | 15 +- .../AuthServiceForgotPasswordTest.php | 102 +++++----- .../Authentication/AuthServiceLoginTest.php | 191 ------------------ .../AuthServiceRegisterTest.php | 70 ++----- tests/Fixtures/MailTracking.php | 1 + tests/Fixtures/User/User.php | 3 +- 13 files changed, 163 insertions(+), 304 deletions(-) delete mode 100644 tests/Feature/Authentication/AuthServiceLoginTest.php diff --git a/composer.json b/composer.json index c531237c7..9134d597d 100644 --- a/composer.json +++ b/composer.json @@ -20,8 +20,9 @@ "require": { "php": "^7.4", "ext-json": "*", + "doctrine/dbal": "^2.10", "illuminate/support": "^6.0|^7.0", - "doctrine/dbal": "^2.10" + "laravel/ui": "^2.0" }, "require-dev": { "mockery/mockery": "^1.3", diff --git a/config/config.php b/config/config.php index 09fa313f8..f5e6762be 100644 --- a/config/config.php +++ b/config/config.php @@ -29,6 +29,20 @@ */ 'provider' => 'sanctum', + + /* + |-------------------------------------------------------------------------- + | Auth frontend app url + |-------------------------------------------------------------------------- + | + |URL used for reset password URL generating. + | + | + */ + + 'frontend_app_url' => env('FRONTEND_APP_URL', env('APP_URL')), + + 'password_reset_url' => env('FRONTEND_APP_URL') . '/password/reset?token={token}&email={email}', ], /* diff --git a/src/Commands/CheckPassport.php b/src/Commands/CheckPassport.php index 37eb69ae1..5492e8b50 100644 --- a/src/Commands/CheckPassport.php +++ b/src/Commands/CheckPassport.php @@ -148,7 +148,7 @@ public function hasPassportClient(): bool } catch (\RuntimeException $e) { $this->warn($e->getMessage()); $this->warn('Hint: php artisan passport:client --personal'); - $this->warn('See: https://laravel.com/docs/6.x/passport#creating-a-personal-access-client'); + $this->warn('See: https://laravel.com/docs/7.x/passport#creating-a-personal-access-client'); return false; } diff --git a/src/Services/AuthService.php b/src/Services/AuthService.php index e74819e52..0baf82cfc 100644 --- a/src/Services/AuthService.php +++ b/src/Services/AuthService.php @@ -31,12 +31,14 @@ public function login(Request $request) throw SanctumUserException::wrongConfiguration(); } - return LoginService::make($request); + $token = LoginService::make($request); + + return $token; } public function register(Request $request) { - return RegisterService::make($request); + return RegisterService::make($request, $this); } public function forgotPassword(Request $request) @@ -72,7 +74,7 @@ public function verify($id, $hash = null) public function resetPassword(Request $request) { - return ResetPasswordService::make($request); + return ResetPasswordService::make($request, $this); } /** diff --git a/src/Services/ForgotPasswordService.php b/src/Services/ForgotPasswordService.php index a0c96245c..f04668ce6 100644 --- a/src/Services/ForgotPasswordService.php +++ b/src/Services/ForgotPasswordService.php @@ -2,6 +2,7 @@ namespace Binaryk\LaravelRestify\Services; +use Illuminate\Auth\Notifications\ResetPassword; use Illuminate\Foundation\Auth\SendsPasswordResetEmails; use Illuminate\Http\Request; @@ -14,6 +15,13 @@ class ForgotPasswordService public static function make(Request $request) { + ResetPassword::createUrlUsing(function ($notifiable, $token) { + $withToken = str_replace(['{token}'], $token, config('restify.auth.password_reset_url')); + $withEmail = str_replace(['{email}'], $notifiable->getEmailForPasswordReset(), $withToken); + + return url($withEmail); + }); + return resolve(static::class)->sendResetLinkEmail($request); } } diff --git a/src/Services/LoginService.php b/src/Services/LoginService.php index 9966b6557..60de0e8ff 100644 --- a/src/Services/LoginService.php +++ b/src/Services/LoginService.php @@ -2,6 +2,7 @@ namespace Binaryk\LaravelRestify\Services; +use Binaryk\LaravelRestify\Events\UserLoggedIn; use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Http\Request; @@ -16,4 +17,32 @@ public static function make(Request $request) { return resolve(static::class)->login($request); } + + public function login(Request $request) + { + $this->validateLogin($request); + + // If the class is using the ThrottlesLogins trait, we can automatically throttle + // the login attempts for this application. We'll key this by the username and + // the IP address of the client making these requests into this application. + if (method_exists($this, 'hasTooManyLoginAttempts') && + $this->hasTooManyLoginAttempts($request)) { + $this->fireLockoutEvent($request); + + return $this->sendLockoutResponse($request); + } + + if ($this->attemptLogin($request)) { + event(new UserLoggedIn($this->guard()->user())); + return $this->guard()->user()->createToken('login'); + } + + // If the login attempt was unsuccessful we will increment the number of attempts + // to login and redirect the user back to the login form. Of course, when this + // user surpasses their maximum number of attempts they will get locked out. + $this->incrementLoginAttempts($request); + + return $this->sendFailedLoginResponse($request); + + } } diff --git a/src/Services/RegisterService.php b/src/Services/RegisterService.php index 3647075c7..a91813095 100644 --- a/src/Services/RegisterService.php +++ b/src/Services/RegisterService.php @@ -19,12 +19,17 @@ */ class RegisterService { + /** + * @var AuthService + */ + protected $authService; + /** * The callback that should be used to create the registered user. * * @var Closure|null */ - public static Closure $creating; + public static $creating; public static $registerFormRequest = RestifyRegisterRequest::class; @@ -34,7 +39,7 @@ public function register(Request $request) $this->validateRegister($payload); - $builder = $this->userQuery(); + $builder = $this->authService->userQuery(); if (false === $builder instanceof Authenticatable) { throw AuthenticatableUserException::wrongInstance(); @@ -57,9 +62,11 @@ public function register(Request $request) return $user; } - public static function make(Request $request) + public static function make(Request $request, AuthService $authService) { - return resolve(static::class)->register($request); + return resolve(static::class) + ->usingAuthService($authService) + ->register($request); } public function validateRegister(array $payload) @@ -78,4 +85,10 @@ public function validateRegister(array $payload) return true; } + + protected function usingAuthService(AuthService $service) { + $this->authService = $service; + + return $this; + } } diff --git a/src/Services/ResetPasswordService.php b/src/Services/ResetPasswordService.php index 2b3f8c13a..a68dbffdc 100644 --- a/src/Services/ResetPasswordService.php +++ b/src/Services/ResetPasswordService.php @@ -12,8 +12,19 @@ class ResetPasswordService { use ResetsPasswords; - public static function make(Request $request) + protected $authService; + + public static function make(Request $request, AuthService $authService) + { + return resolve(static::class) + ->reset($request); + } + + + protected function usingAuthService(AuthService $authService) { - return resolve(static::class)->reset($request); + $this->authService = $authService; + + return $this; } } diff --git a/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php b/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php index 763ea23f3..1c1b6c55d 100644 --- a/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php +++ b/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php @@ -3,16 +3,19 @@ namespace Binaryk\LaravelRestify\Tests\Feature\Authentication; use Binaryk\LaravelRestify\Events\UserLoggedIn; -use Binaryk\LaravelRestify\Exceptions\Eloquent\EntityNotFoundException; -use Binaryk\LaravelRestify\Exceptions\PasswordResetInvalidTokenException; +use Binaryk\LaravelRestify\Notifications\PasswordResetNotification; use Binaryk\LaravelRestify\Services\AuthService; +use Binaryk\LaravelRestify\Services\RegisterService; use Binaryk\LaravelRestify\Tests\Fixtures\MailTracking; use Binaryk\LaravelRestify\Tests\Fixtures\User\User; use Binaryk\LaravelRestify\Tests\IntegrationTest; use Illuminate\Auth\Events\PasswordReset; use Illuminate\Auth\Events\Registered; +use Illuminate\Auth\Notifications\ResetPassword; use Illuminate\Foundation\Testing\Concerns\InteractsWithContainer; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Event; +use Illuminate\Support\Facades\Notification; use Illuminate\Support\Str; use Illuminate\Validation\ValidationException; @@ -33,100 +36,89 @@ protected function setUp(): void { parent::setUp(); $this->setUpMailTracking(); - AuthService::$registerFormRequest = null; + RegisterService::$registerFormRequest = null; $this->authService = resolve(AuthService::class); - } - - public function test_invalid_email_in_payload() - { - $this->expectException(ValidationException::class); - $this->authService->sendResetPasswordLinkEmail('invalid_email'); + $this->app['config']->set('restify.auth.provider', 'sanctum'); + $this->app['config']->set('restify.auth.frontend_app_url', 'https://laravel-restify.dev'); + $this->app['config']->set('restify.auth.password_reset_url', 'https://laravel-restify.dev/password/reset?token={token}&email={email}'); } public function test_email_was_sent_and_contain_token() { + Notification::fake(); + $user = $this->register(); - $this->authService->sendResetPasswordLinkEmail($user->email); - if ($this->lastEmail()) { - $lastEmail = $this->lastEmail()->getBody(); - preg_match_all('/token=([\w\.]*)/i', $lastEmail, $data); - $token = $data[1][0]; - - $this->assertEmailsSent(1); - $this->assertEmailTo($user->email); - $this->assertNotNull($token); - } + $request = new Request([], []); + $request->merge(['email' => $user->email]); + + $this->authService->forgotPassword($request); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $this->assertNotEmpty($notification->token); + return true; + }); } public function test_reset_password_invalid_payload() { $this->expectException(ValidationException::class); - $this->authService->resetPassword([ + $request = new Request([], []); + $request->merge([ 'email' => null, 'password' => 'password', 'password_confirmation' => 'password', 'token' => 'secret', ]); - } - - public function test_reset_password_invalid_token() - { - $user = $this->register(); - $this->expectException(PasswordResetInvalidTokenException::class); - $this->authService->resetPassword([ - 'email' => $user->email, - 'password' => 'password', - 'password_confirmation' => 'password', - 'token' => 'secret', - ]); - } - - public function test_reset_password_invalid_user() - { - $this->expectException(EntityNotFoundException::class); - $this->authService->resetPassword([ - 'email' => 'random@test.com', - 'password' => 'password', - 'password_confirmation' => 'password', - 'token' => 'secret', - ]); + $this->authService->resetPassword($request); } public function test_reset_password_successfully() { + Notification::fake(); $user = $this->register(); $this->authService->verify($user->id, sha1($user->email)); - $this->authService->sendResetPasswordLinkEmail($user->email); - if ($this->lastEmail()) { - $lastEmail = $this->lastEmail()->getBody(); - preg_match_all('/token=([\w\.]*)/i', $lastEmail, $data); - $token = $data[1][0]; + + $request = new Request([], []); + $request->merge(['email' => $user->email]); + + $this->authService->forgotPassword($request); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $token = $notification->token; $password = Str::random(10); - $this->authService->resetPassword([ + $request = new Request([], []); + $request->merge([ 'email' => $user->email, 'password' => $password, 'password_confirmation' => $password, 'token' => $token, ]); + $this->authService->resetPassword($request); + Event::assertDispatched(PasswordReset::class, function ($e) use ($user) { $this->assertEquals($e->user->email, $user->email); return $e->user instanceof User; }); - $this->authService->login([ + $request = new Request([], []); + $request->merge([ 'email' => $user->email, 'password' => $password, ]); + $this->authService->login($request); + Event::assertDispatched(UserLoggedIn::class, function ($e) use ($user) { $this->assertEquals($e->user->email, $user->email); return $e->user instanceof User; }); - } + + return true; + }); } public function register() @@ -139,14 +131,18 @@ public function register() $this->app->instance(User::class, new User); + $request = new Request([], []); + $user = [ 'name' => 'Eduard Lupacescu', 'email' => 'eduard.lupacescu@binarcode.com', - 'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', + 'password' => 'secret!', 'remember_token' => Str::random(10), ]; - $this->authService->register($user); + $request->merge($user); + + $this->authService->register($request); return User::query()->get()->last(); } diff --git a/tests/Feature/Authentication/AuthServiceLoginTest.php b/tests/Feature/Authentication/AuthServiceLoginTest.php deleted file mode 100644 index e83c42b75..000000000 --- a/tests/Feature/Authentication/AuthServiceLoginTest.php +++ /dev/null @@ -1,191 +0,0 @@ - - */ -class AuthServiceLoginTest extends IntegrationTest -{ - /** - * @var AuthService - */ - protected $authService; - - protected function setUp(): void - { - parent::setUp(); - $this->authService = resolve(AuthService::class); - } - - public function test_password_broker_facade() - { - $this->assertInstanceOf(PasswordBroker::class, $this->authService->broker()); - } - - public function test_login_throw_invalid_credentials_exception() - { - $this->expectException(CredentialsDoesntMatch::class); - Auth::shouldReceive('attempt') - ->andReturnFalse(); - $this->authService->login([ - 'email' => 'random@random.com', - 'password' => 'secret', - ]); - } - - public function test_user_did_not_verified_email() - { - $this->expectException(UnverifiedUser::class); - $this->expectExceptionMessage('The email is not verified'); - - $userMustVerify = (new class extends User implements MustVerifyEmail { - use \Illuminate\Auth\MustVerifyEmail; - }); - - $userMustVerify->fill([ - 'email' => 'test@mail.com', - 'email_verified_at' => null, - ]); - - Auth::shouldReceive('attempt') - ->andReturnTrue(); - - Auth::shouldReceive('user') - ->andReturn($userMustVerify); - - $this->authService->login([]); - } - - public function test_login_user_did_not_user_passport_trait_or_not_implement_pasportable() - { - $this->app['config']->set('restify.auth.provider', 'passport'); - $this->expectException(PassportUserException::class); - $userMustVerify = (new class extends User implements MustVerifyEmail { - use \Illuminate\Auth\MustVerifyEmail; - }); - - $userMustVerify->fill([ - 'email' => 'test@mail.com', - 'email_verified_at' => Carbon::now(), - ]); - - Auth::shouldReceive('attempt') - ->andReturnTrue(); - - Auth::shouldReceive('user') - ->andReturn($userMustVerify); - - $this->authService->login(); - } - - public function test_login_user_did_not_user_passport_trait_or_not_implement_sanctumable() - { - $this->app['config']->set('restify.auth.provider', 'sanctum'); - $this->expectException(SanctumUserException::class); - - $userMustVerify = (new class extends User implements MustVerifyEmail { - use \Illuminate\Auth\MustVerifyEmail; - }); - - $userMustVerify->fill([ - 'email' => 'test@mail.com', - 'email_verified_at' => Carbon::now(), - ]); - - Auth::shouldReceive('attempt') - ->andReturnTrue(); - - Auth::shouldReceive('user') - ->andReturn($userMustVerify); - - $this->authService->login(); - } - - public function test_login_with_success() - { - Event::fake([ - UserLoggedIn::class, - ]); - $user = (new class extends User implements MustVerifyEmail, Passportable { - use \Illuminate\Auth\MustVerifyEmail; - }); - - $user->fill([ - 'email' => 'test@mail.com', - 'email_verified_at' => Carbon::now(), - ]); - - Auth::shouldReceive('attempt') - ->andReturnTrue(); - - Auth::shouldReceive('user') - ->andReturn($user); - - $authToken = $this->authService->login(); - $this->assertEquals('token', $authToken); - - Event::assertDispatched(UserLoggedIn::class, function ($e) use ($user) { - $this->assertEquals($e->user->email, $user->email); - - return $e->user instanceof User; - }); - } - - public function test_logout_success() - { - Event::fake(); - $this->app['config']->set('restify.auth.provider', 'passport'); - - $user = (new class extends \ Binaryk\LaravelRestify\Tests\Fixtures\User\User { - public function tokens() - { - $builder = \Mockery::mock(Builder::class); - $tokens = [(new class { - public function revoke() - { - return true; - } - })]; - - $builder->shouldReceive('get')->andReturn(collect($tokens)); - - return $builder; - } - }); - - Auth::shouldReceive('user') - ->andReturn($user); - - $this->authService->logout(); - - Event::assertDispatched(UserLogout::class); - } - - public function test_logout_unauthenticated() - { - Auth::shouldReceive('user') - ->andReturn(null); - - $this->expectException(AuthenticatableUserException::class); - $this->authService->logout(); - } -} diff --git a/tests/Feature/Authentication/AuthServiceRegisterTest.php b/tests/Feature/Authentication/AuthServiceRegisterTest.php index c2e292843..1c83363ef 100644 --- a/tests/Feature/Authentication/AuthServiceRegisterTest.php +++ b/tests/Feature/Authentication/AuthServiceRegisterTest.php @@ -5,7 +5,6 @@ use Binaryk\LaravelRestify\Contracts\Passportable; use Binaryk\LaravelRestify\Exceptions\AuthenticatableUserException; use Binaryk\LaravelRestify\Exceptions\Eloquent\EntityNotFoundException; -use Binaryk\LaravelRestify\Http\Requests\RestifyRegisterRequest; use Binaryk\LaravelRestify\Models\LaravelRestifyModel; use Binaryk\LaravelRestify\Services\AuthService; use Binaryk\LaravelRestify\Tests\Fixtures\User\SimpleUser; @@ -15,9 +14,9 @@ use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Events\Verified; use Illuminate\Foundation\Testing\Concerns\InteractsWithContainer; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Event; use Illuminate\Support\Str; -use Illuminate\Validation\ValidationException; /** * @author Eduard Lupacescu @@ -49,8 +48,13 @@ public function test_register_throw_user_not_authenticatable() 'remember_token' => Str::random(10), ]; + $request = new Request([], []); + + $request->merge($user); + + $this->expectException(AuthenticatableUserException::class); - $this->authService->register($user); + $this->authService->register($request); } public function test_user_query_throw_container_does_not_have_model_reflection_exception() @@ -83,7 +87,11 @@ public function test_register_successfully() 'remember_token' => Str::random(10), ]; - $this->authService->register($user); + $request = new Request([], []); + + $request->merge($user); + + $this->authService->register($request); Event::assertDispatched(Registered::class, function ($e) use ($user) { $this->assertEquals($e->user->email, $user['email']); @@ -112,7 +120,11 @@ public function test_verify_user_throw_hash_not_match() 'remember_token' => Str::random(10), ]; - $this->authService->register($user); + $request = new Request([], []); + + $request->merge($user); + + $this->authService->register($request); $lastUser = User::query()->get()->last(); $this->expectException(AuthorizationException::class); @@ -136,7 +148,11 @@ public function test_verify_user_successfully() 'remember_token' => Str::random(10), ]; - $this->authService->register($user); + $request = new Request([], []); + + $request->merge($user); + + $this->authService->register($request); $lastUser = User::query()->get()->last(); $this->assertNull($lastUser->email_verified_at); @@ -149,46 +165,4 @@ public function test_verify_user_successfully() return $e->user instanceof \ Binaryk\LaravelRestify\Tests\Fixtures\User\User; }); } - - public function test_register_invalid_payload_is_validated_on_register() - { - $user = [ - 'name' => 'Eduard Lupacescu', - 'email' => 'eduard.lupacescu@binarcode.com', - 'password' => 'password', - 'remember_token' => Str::random(10), - ]; - - AuthService::$registerFormRequest = RestifyRegisterRequest::class; - $this->expectException(ValidationException::class); - $this->authService->validateRegister($user); - AuthService::$registerFormRequest = null; - } - - public function test_register_payload_is_validated_on_register() - { - $user = [ - 'name' => 'Eduard Lupacescu', - 'email' => 'eduard.lupacescu@binarcode.com', - 'password' => 'password', - 'password_confirmation' => 'password', - 'remember_token' => Str::random(10), - ]; - - $this->assertTrue($this->authService->validateRegister($user)); - } - - public function test_invalid_payload_not_validated_because_validation_disabled() - { - AuthService::$registerFormRequest = null; - - $user = [ - 'name' => 'Eduard Lupacescu', - 'email' => 'eduard.lupacescu@binarcode.com', - 'password' => 'password', - 'remember_token' => Str::random(10), - ]; - - $this->assertTrue($this->authService->validateRegister($user)); - } } diff --git a/tests/Fixtures/MailTracking.php b/tests/Fixtures/MailTracking.php index 22e2dfc40..c08b240cd 100644 --- a/tests/Fixtures/MailTracking.php +++ b/tests/Fixtures/MailTracking.php @@ -2,6 +2,7 @@ namespace Binaryk\LaravelRestify\Tests\Fixtures; +use Illuminate\Mail\Mailer; use Illuminate\Support\Facades\Mail; use Swift_Events_EventListener; use Swift_Message; diff --git a/tests/Fixtures/User/User.php b/tests/Fixtures/User/User.php index 828b01778..b54d37622 100644 --- a/tests/Fixtures/User/User.php +++ b/tests/Fixtures/User/User.php @@ -4,6 +4,7 @@ use Binaryk\LaravelRestify\Contracts\Passportable; use Binaryk\LaravelRestify\Contracts\RestifySearchable; +use Binaryk\LaravelRestify\Contracts\Sanctumable; use Binaryk\LaravelRestify\Tests\Fixtures\Post\Post; use Binaryk\LaravelRestify\Traits\InteractWithSearch; use Illuminate\Contracts\Auth\MustVerifyEmail; @@ -15,7 +16,7 @@ /** * @author Eduard Lupacescu */ -class User extends Authenticatable implements Passportable, MustVerifyEmail, RestifySearchable +class User extends Authenticatable implements Sanctumable, MustVerifyEmail, RestifySearchable { use \Illuminate\Auth\MustVerifyEmail; use Notifiable, From 30eb4d0123440116b9076f2ce091635f3f3fc892 Mon Sep 17 00:00:00 2001 From: Lupacescu Eduard Date: Sun, 10 May 2020 17:50:28 +0300 Subject: [PATCH 4/4] Apply fixes from StyleCI (#173) --- config/config.php | 2 +- src/Services/LoginService.php | 2 +- src/Services/RegisterService.php | 3 ++- src/Services/ResetPasswordService.php | 1 - tests/Feature/Authentication/AuthServiceForgotPasswordTest.php | 2 +- tests/Feature/Authentication/AuthServiceRegisterTest.php | 1 - tests/Fixtures/MailTracking.php | 1 - tests/Fixtures/User/User.php | 1 - 8 files changed, 5 insertions(+), 8 deletions(-) diff --git a/config/config.php b/config/config.php index f5e6762be..8c10001d1 100644 --- a/config/config.php +++ b/config/config.php @@ -42,7 +42,7 @@ 'frontend_app_url' => env('FRONTEND_APP_URL', env('APP_URL')), - 'password_reset_url' => env('FRONTEND_APP_URL') . '/password/reset?token={token}&email={email}', + 'password_reset_url' => env('FRONTEND_APP_URL').'/password/reset?token={token}&email={email}', ], /* diff --git a/src/Services/LoginService.php b/src/Services/LoginService.php index 60de0e8ff..909b77e18 100644 --- a/src/Services/LoginService.php +++ b/src/Services/LoginService.php @@ -34,6 +34,7 @@ public function login(Request $request) if ($this->attemptLogin($request)) { event(new UserLoggedIn($this->guard()->user())); + return $this->guard()->user()->createToken('login'); } @@ -43,6 +44,5 @@ public function login(Request $request) $this->incrementLoginAttempts($request); return $this->sendFailedLoginResponse($request); - } } diff --git a/src/Services/RegisterService.php b/src/Services/RegisterService.php index a91813095..1681c078a 100644 --- a/src/Services/RegisterService.php +++ b/src/Services/RegisterService.php @@ -86,7 +86,8 @@ public function validateRegister(array $payload) return true; } - protected function usingAuthService(AuthService $service) { + protected function usingAuthService(AuthService $service) + { $this->authService = $service; return $this; diff --git a/src/Services/ResetPasswordService.php b/src/Services/ResetPasswordService.php index a68dbffdc..3597fe379 100644 --- a/src/Services/ResetPasswordService.php +++ b/src/Services/ResetPasswordService.php @@ -20,7 +20,6 @@ public static function make(Request $request, AuthService $authService) ->reset($request); } - protected function usingAuthService(AuthService $authService) { $this->authService = $authService; diff --git a/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php b/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php index 1c1b6c55d..eabb4fb3a 100644 --- a/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php +++ b/tests/Feature/Authentication/AuthServiceForgotPasswordTest.php @@ -3,7 +3,6 @@ namespace Binaryk\LaravelRestify\Tests\Feature\Authentication; use Binaryk\LaravelRestify\Events\UserLoggedIn; -use Binaryk\LaravelRestify\Notifications\PasswordResetNotification; use Binaryk\LaravelRestify\Services\AuthService; use Binaryk\LaravelRestify\Services\RegisterService; use Binaryk\LaravelRestify\Tests\Fixtures\MailTracking; @@ -55,6 +54,7 @@ public function test_email_was_sent_and_contain_token() Notification::assertSentTo($user, ResetPassword::class, function ($notification) { $this->assertNotEmpty($notification->token); + return true; }); } diff --git a/tests/Feature/Authentication/AuthServiceRegisterTest.php b/tests/Feature/Authentication/AuthServiceRegisterTest.php index 1c83363ef..68ac30108 100644 --- a/tests/Feature/Authentication/AuthServiceRegisterTest.php +++ b/tests/Feature/Authentication/AuthServiceRegisterTest.php @@ -52,7 +52,6 @@ public function test_register_throw_user_not_authenticatable() $request->merge($user); - $this->expectException(AuthenticatableUserException::class); $this->authService->register($request); } diff --git a/tests/Fixtures/MailTracking.php b/tests/Fixtures/MailTracking.php index c08b240cd..22e2dfc40 100644 --- a/tests/Fixtures/MailTracking.php +++ b/tests/Fixtures/MailTracking.php @@ -2,7 +2,6 @@ namespace Binaryk\LaravelRestify\Tests\Fixtures; -use Illuminate\Mail\Mailer; use Illuminate\Support\Facades\Mail; use Swift_Events_EventListener; use Swift_Message; diff --git a/tests/Fixtures/User/User.php b/tests/Fixtures/User/User.php index b54d37622..b072ec989 100644 --- a/tests/Fixtures/User/User.php +++ b/tests/Fixtures/User/User.php @@ -2,7 +2,6 @@ namespace Binaryk\LaravelRestify\Tests\Fixtures\User; -use Binaryk\LaravelRestify\Contracts\Passportable; use Binaryk\LaravelRestify\Contracts\RestifySearchable; use Binaryk\LaravelRestify\Contracts\Sanctumable; use Binaryk\LaravelRestify\Tests\Fixtures\Post\Post;