2015-12-18 10 views
6

Sono riuscito a regolare l'autorizzazione Laravel predefinita in modo che funzionasse come un'API per il mio AngularJS, e finora tutto funziona correttamente. Puoi andare su/reset e inserire un'e-mail e ricevere un'e-mail con un link per reimpostare la password che va a/reset/{token} e se non ricevi errori di convalida, la tua password sarà cambiata con successo.Laravel 5.1/AngularJS: Reimposta password nella vista Angolare (come convalidare il token CSRF?)

L'unico problema è che sto usando una vista Angolare, non c'è davvero nulla che convalida il token e si assicuri che non sia solo un messaggio senza senso prima di mostrare lo stato reset-password. Ho provato ad aggiungere questo alla parte superiore del controller:

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

... che sarebbe fondamentalmente vedere se il token è l'attuale token CSRF, ma che non funziona perché quando il link di reimpostazione password viene inviata la CSRF token è cambiato o qualcosa ... non è più il token della sessione.

Qualcuno ha qualche idea su come posso farlo? Voglio semplicemente reindirizzare l'utente se il token inserito nell'url su "/ reset /: token" non è valido.

Ecco il mio codice ..

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' 
     }) 

questo è nel tratto ResetsPassword in ResetsPassword.php. La maggior parte era già impostata ma ho rimosso/modificato molto per funzionare come un'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's 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's password. 
    */ 
    protected function resetPassword($user, $password) 
    { 
     $user->password = bcrypt($password); 

     $user->save(); 
    } 

risposta

5

Questo calcolato.

Per chiunque abbia un problema simile ... Ecco come l'ho risolto (probabilmente lo renderà migliore in seguito, ma per ora funziona).

Ho aggiunto un altro URL per l'API che è reset/password e richiede una richiesta GET. Ho passato il token in base al valore $stateParams e se quel token non esiste nella tabella password_resets O se quel token esiste ed è scaduto, restituire alcuni errori. Nel controller, gestisco gli errori con un reindirizzamento. Ancora una volta non penso che questo sia l'ideale, perché chiunque guardi alla fonte potrebbe cambiarlo e rimuovere il reindirizzamento, quindi devo trovare un modo migliore per implementarlo.

Ma ancora, per ora funziona ed è comunque una soluzione.

ResetsPasswords.php (aggiunto un metodo per la richiesta GET):

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\'s expired.' 
        ] 
       ], 401); 
      } 
     } else { 
      return response()->json([ 
       'error' => [ 
        'message' => 'Token is invalid.' 
       ] 
      ], 401); 
     } 
    } 

e nei miei resetPasswordController.js ho solo controllare se i respose restituisce 'successo' o qualsiasi delle risposte 'errore', e se si tratta di una risposta di "errore" farei semplicemente qualcosa come $state.go('reset') che li reindirizzerebbe nuovamente al modulo "password dimenticata" in cui inseriscono la loro e-mail per ottenere un link per la reimpostazione della password.

EDIT:

Ho pensato che il controllo per un token valido il controllore era male, perché sarebbe sempre caricare la visualizzazione almeno per una frazione di secondo. Stavo cercando una sorta di middleware, ma poi ho dimenticato che stavo già usando il pacchetto angular-permission, che funge da middleware front-end.

Ho definito un ruolo isTokenValid e l'ho impostato in modo tale che richiami automaticamente una funzione nel authService che ho e ottenga una risposta dalla mia API in base alla validità del token. Se ha successo, il ruolo consente all'utente di entrare nello stato. In caso contrario, reindirizza allo stato reset. Ciò impedisce la visualizzazione della visualizzazione per la frazione di secondo. Atti molto simili al middleware Laravel.

Unico problema dal momento che sta accadendo sul front-end, qualsiasi hacker può ignorarlo ma va bene perché il codice lato server è ancora lì quindi anche se accedono alla vista non possono fare nulla con le password che entrano perché il token non è ancora valido e deve corrispondere a un particolare utente.

Un altro miglioramento sarebbe trovare un modo per disabilitare la visualizzazione anche senza l'implementazione del middleware front-end. Forse lo aggiornerò di nuovo se trovo un modo per farlo.

Attuazione

Il ruolo:

 .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; 
     }); 

E lo Stato:

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

Speranza che aiuta chiunque con lo stesso problema.

+0

Questa è una domanda utile e illustrazione della tecnica per chiunque sviluppi con Laravel e Angular. Grazie per la pubblicazione. – delatbabel

Problemi correlati