PasswordBroker.php 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace Illuminate\Auth\Passwords;
  3. use Closure;
  4. use Illuminate\Support\Arr;
  5. use UnexpectedValueException;
  6. use Illuminate\Contracts\Auth\UserProvider;
  7. use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
  8. use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
  9. class PasswordBroker implements PasswordBrokerContract
  10. {
  11. /**
  12. * The password token repository.
  13. *
  14. * @var \Illuminate\Auth\Passwords\TokenRepositoryInterface
  15. */
  16. protected $tokens;
  17. /**
  18. * The user provider implementation.
  19. *
  20. * @var \Illuminate\Contracts\Auth\UserProvider
  21. */
  22. protected $users;
  23. /**
  24. * The custom password validator callback.
  25. *
  26. * @var \Closure
  27. */
  28. protected $passwordValidator;
  29. /**
  30. * Create a new password broker instance.
  31. *
  32. * @param \Illuminate\Auth\Passwords\TokenRepositoryInterface $tokens
  33. * @param \Illuminate\Contracts\Auth\UserProvider $users
  34. * @return void
  35. */
  36. public function __construct(TokenRepositoryInterface $tokens,
  37. UserProvider $users)
  38. {
  39. $this->users = $users;
  40. $this->tokens = $tokens;
  41. }
  42. /**
  43. * Send a password reset link to a user.
  44. *
  45. * @param array $credentials
  46. * @return string
  47. */
  48. public function sendResetLink(array $credentials)
  49. {
  50. // First we will check to see if we found a user at the given credentials and
  51. // if we did not we will redirect back to this current URI with a piece of
  52. // "flash" data in the session to indicate to the developers the errors.
  53. $user = $this->getUser($credentials);
  54. if (is_null($user)) {
  55. return static::INVALID_USER;
  56. }
  57. // Once we have the reset token, we are ready to send the message out to this
  58. // user with a link to reset their password. We will then redirect back to
  59. // the current URI having nothing set in the session to indicate errors.
  60. $user->sendPasswordResetNotification(
  61. $this->tokens->create($user)
  62. );
  63. return static::RESET_LINK_SENT;
  64. }
  65. /**
  66. * Reset the password for the given token.
  67. *
  68. * @param array $credentials
  69. * @param \Closure $callback
  70. * @return mixed
  71. */
  72. public function reset(array $credentials, Closure $callback)
  73. {
  74. // If the responses from the validate method is not a user instance, we will
  75. // assume that it is a redirect and simply return it from this method and
  76. // the user is properly redirected having an error message on the post.
  77. $user = $this->validateReset($credentials);
  78. if (! $user instanceof CanResetPasswordContract) {
  79. return $user;
  80. }
  81. $password = $credentials['password'];
  82. // Once the reset has been validated, we'll call the given callback with the
  83. // new password. This gives the user an opportunity to store the password
  84. // in their persistent storage. Then we'll delete the token and return.
  85. $callback($user, $password);
  86. $this->tokens->delete($user);
  87. return static::PASSWORD_RESET;
  88. }
  89. /**
  90. * Validate a password reset for the given credentials.
  91. *
  92. * @param array $credentials
  93. * @return \Illuminate\Contracts\Auth\CanResetPassword|string
  94. */
  95. protected function validateReset(array $credentials)
  96. {
  97. if (is_null($user = $this->getUser($credentials))) {
  98. return static::INVALID_USER;
  99. }
  100. if (! $this->validateNewPassword($credentials)) {
  101. return static::INVALID_PASSWORD;
  102. }
  103. if (! $this->tokens->exists($user, $credentials['token'])) {
  104. return static::INVALID_TOKEN;
  105. }
  106. return $user;
  107. }
  108. /**
  109. * Set a custom password validator.
  110. *
  111. * @param \Closure $callback
  112. * @return void
  113. */
  114. public function validator(Closure $callback)
  115. {
  116. $this->passwordValidator = $callback;
  117. }
  118. /**
  119. * Determine if the passwords match for the request.
  120. *
  121. * @param array $credentials
  122. * @return bool
  123. */
  124. public function validateNewPassword(array $credentials)
  125. {
  126. if (isset($this->passwordValidator)) {
  127. list($password, $confirm) = [
  128. $credentials['password'],
  129. $credentials['password_confirmation'],
  130. ];
  131. return call_user_func(
  132. $this->passwordValidator, $credentials
  133. ) && $password === $confirm;
  134. }
  135. return $this->validatePasswordWithDefaults($credentials);
  136. }
  137. /**
  138. * Determine if the passwords are valid for the request.
  139. *
  140. * @param array $credentials
  141. * @return bool
  142. */
  143. protected function validatePasswordWithDefaults(array $credentials)
  144. {
  145. list($password, $confirm) = [
  146. $credentials['password'],
  147. $credentials['password_confirmation'],
  148. ];
  149. return $password === $confirm && mb_strlen($password) >= 6;
  150. }
  151. /**
  152. * Get the user for the given credentials.
  153. *
  154. * @param array $credentials
  155. * @return \Illuminate\Contracts\Auth\CanResetPassword|null
  156. *
  157. * @throws \UnexpectedValueException
  158. */
  159. public function getUser(array $credentials)
  160. {
  161. $credentials = Arr::except($credentials, ['token']);
  162. $user = $this->users->retrieveByCredentials($credentials);
  163. if ($user && ! $user instanceof CanResetPasswordContract) {
  164. throw new UnexpectedValueException('User must implement CanResetPassword interface.');
  165. }
  166. return $user;
  167. }
  168. /**
  169. * Create a new password reset token for the given user.
  170. *
  171. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  172. * @return string
  173. */
  174. public function createToken(CanResetPasswordContract $user)
  175. {
  176. return $this->tokens->create($user);
  177. }
  178. /**
  179. * Delete password reset tokens of the given user.
  180. *
  181. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  182. * @return void
  183. */
  184. public function deleteToken(CanResetPasswordContract $user)
  185. {
  186. $this->tokens->delete($user);
  187. }
  188. /**
  189. * Validate the given password reset token.
  190. *
  191. * @param \Illuminate\Contracts\Auth\CanResetPassword $user
  192. * @param string $token
  193. * @return bool
  194. */
  195. public function tokenExists(CanResetPasswordContract $user, $token)
  196. {
  197. return $this->tokens->exists($user, $token);
  198. }
  199. /**
  200. * Get the password reset token repository implementation.
  201. *
  202. * @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
  203. */
  204. public function getRepository()
  205. {
  206. return $this->tokens;
  207. }
  208. }