Laravel 5.1 / AngularJS: Reset password in Angular view (how to check CSRF token?)

I was able to configure the default Laravel so that it works as an API for my AngularJS, and so far everything is working fine. You can go to / reset and enter an email and send an email with the reset password, which will be indicated in / reset / {token}, and if you do not receive any verification errors, your password will be successfully changed.

The only problem is that I am using the Angular view, there really is nothing to confirm the token, and make sure it is not just gibbering before showing the reset-password state. I tried adding this to the top of the controller:

  if ($stateParams.token != $cookies.get('XSRF_TOKEN')) { $state.go('reset'); } 

... which will basically see if the token is the current CSRF token, but this does not work, because when the reset password is sent, the CSRF token changes or something else ... it is no longer the token from the session.

Anyone have any ideas how I can do this? I want to simply redirect the user if the token entered in the url to `/ reset /: token 'is invalid.

Here is my code ..

App.js:

  .state('reset', { url: '/reset', data: { permissions: { except: ['isLoggedIn'], redirectTo: 'user.dashboard' } }, templateUrl: 'views/auth/forgot-password.html', controller: 'ForgotPasswordController as forgot' }) .state('reset-password', { url: '/reset/:token', data: { permissions: { except: ['isLoggedIn'], redirectTo: 'user.dashboard' } }, templateUrl: 'views/auth/reset-password.html', controller: 'ResetPasswordController as reset' }) 

This is the value of ResetsPassword in ResetsPassword.php. Most have already been configured, but I removed / changed a lot to work as an API:

  /** * Send a reset link to the given user. */ public function postEmail(EmailRequest $request) { $response = Password::sendResetLink($request->only('email'), function (Message $message) { $message->subject($this->getEmailSubject()); }); switch ($response) { case Password::RESET_LINK_SENT: return; case Password::INVALID_USER: return response()->json([ 'denied' => 'We couldn\'t find your account with that information.' ], 404); } } /** * Get the e-mail subject line to be used for the reset link email. */ protected function getEmailSubject() { return property_exists($this, 'subject') ? $this->subject : 'Your Password Reset Link'; } /** * Reset the given user password. */ public function postReset(ResetRequest $request) { $credentials = $request->only( 'password', 'password_confirmation', 'token' ); $response = Password::reset($credentials, function ($user, $password) { $this->resetPassword($user, $password); }); switch ($response) { case Password::PASSWORD_RESET: return; default: return response()->json([ 'error' => [ 'message' => 'Could not reset password' ] ], 400); } } /** * Reset the given user password. */ protected function resetPassword($user, $password) { $user->password = bcrypt($password); $user->save(); } 
+6
source share
1 answer

Figured it out.

For those who have a similar problem ... Here's how I solved it (maybe it will be better after that, but for now it works).

I added another url for the API, which is reset/password , and it accepts a GET request. I pass him a token based on the value of $stateParams , and if this token does not exist in the password_resets table OR, if this token exists and expired, return some errors. In the controller, I handle errors using redirection. Again, I don't think this is ideal, because anyone looking at the source can change it and remove the redirect, so I need to find a better way to implement this.

But then again, while it works, and this solution nonetheless.

ResetsPasswords.php (a request for receipt method has been added):

 public function verifyToken(Request $request) { $user = DB::table('password_resets')->where('token', $request->only('token'))->first(); if ($user) { if ($user->created_at > Carbon::now()->subHours(2)) { return response()->json([ 'success' => [ 'message' => 'Token is valid and not expired.' ] ], 200); } else { return response()->json([ 'error' => [ 'message' => 'Token is valid but it\ expired.' ] ], 401); } } else { return response()->json([ 'error' => [ 'message' => 'Token is invalid.' ] ], 401); } } 

and in my resetPasswordController.js I just check if the respos returns β€œsuccess” or any of the answers β€œerror”, and if it is the answer β€œerror”, I would just do something like $state.go('reset') , which would redirect them back to the "forgotten password" form, where they enter their email address to get a reset link.

EDIT:

I figured checking the correct token in the controller was bad, because it would always load the view for at least a split second. I searched for some middleware, but then I forgot that I already used the angular-permission package, which acts as a front-end middleware.

I defined the role isTokenValid and configured it so that it automatically calls the function in authService that I have and receives a response from my API based on the validity of the token. If successful, the role allows the user to enter a state. Otherwise, it is redirected to the reset state. This prevents the presentation from showing for a second of a second. Acts very similar to Laravel middleware.

The only problem is that this happens on the front panel, any hacker can get around this, but this is normal, because the server-side code still exists, even if they access the view, which they can do nothing with passwords that they introduce. the token is still invalid and must match a specific user.

Another improvement is to find a way to prevent browsing even without middleware. Perhaps I will update it again if I find a way to do this.

Implementation

Role:

  .defineRole('isTokenValid', function(stateParams) { var token = stateParams.token; var deferred = $q.defer(); authService.verifyToken(token) .then(function(res) { if (res.success) { deferred.resolve(); } }, function(res) { if (res.error) { deferred.reject(); } }); return deferred.promise; }); 

And condition:

  .state('reset-password', { url: '/reset/:token', data: { permissions: { only: ['isTokenValid'], redirectTo: 'reset' } }, templateUrl: 'views/auth/reset-password.html', controller: 'ResetPasswordController as reset' }) 

Hope this helps anyone who has the same issue.

+5
source

All Articles