2015-12-18 44 views
6

Udało mi się dostosować domyślne uwierzytelnienie Laravel, aby działał jako interfejs API dla mojego AngularJS, i jak na razie wszystko działa dobrze. Można przejść do/resetować i wpisać adres e-mail, a następnie wysłać e-mail z linkiem do resetowania hasła, który przechodzi do/reset/{token}, a jeśli nie otrzymasz żadnych błędów sprawdzania poprawności, twoje hasło zostanie pomyślnie zmienione.Laravel 5.1/AngularJS: Zresetuj hasło w widoku kątowym (jak sprawdzić token CSRF?)

Jedynym problemem jest to, że używam widoku kątowego, tak naprawdę nie ma nic sprawdzania poprawności tokena i upewniania się, że nie jest to zwykły bełkot, zanim pojawi się stan reset-password. Próbowałem, dodając to do górnej części kontrolera:

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

... co w zasadzie zobaczyć jeśli znacznik jest obecny CSRF żeton, ale to nie działa, ponieważ kiedy link resetowania hasła zostanie wysłana CSRF zmiana tokena lub coś takiego ... to już nie token z sesji.

Ktoś ma jakieś pomysły, jak mogę to zrobić? Chcę przekierować użytkownika, jeśli token wprowadzony w url na `/ reset /: token 'jest nieprawidłowy.

Oto mój kod ..

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

Jest to cechą ResetsPassword w ResetsPassword.php. Większość była już skonfigurowana, ale usunąłem/zmieniłem wiele, aby działać jako interfejs 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(); 
    } 

Odpowiedz

5

Wymyśliłem to.

Dla każdego, kto ma podobny problem ... Oto jak go rozwiązałem (prawdopodobnie sprawi, że będzie on lepszy później, ale na razie działa).

Dodałem kolejny adres URL interfejsu API, który jest reset/password i pobiera żądanie GET. Przesyłam token na podstawie wartości $stateParams i jeśli token nie istnieje w tabeli password_resets LUB jeśli ten token istnieje i wygasł, zwróć kilka błędów. W kontrolerze obsługuję błędy za pomocą przekierowania. Ponownie nie sądzę, że jest to idealne rozwiązanie, ponieważ każdy, kto szuka źródła, może go zmienić i usunąć przekierowanie, więc muszę znaleźć lepszy sposób na jego wdrożenie.

Ale znowu, na razie działa i jest to jednak rozwiązanie.

ResetsPasswords.php (dodane metodę żądanie 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); 
     } 
    } 

iw moich resetPasswordController.js ja po prostu sprawdzić, czy 'sukces' The respose Zwraca lub którykolwiek z odpowiedziami 'błędu', a jeśli jest to odpowiedź "błąd", po prostu zrobiłbym coś takiego, jak $state.go('reset'), który przekieruje ich z powrotem do formularza "zapomniałem hasła", gdzie wpiszą adres e-mail, aby uzyskać link do resetowania hasła.

EDIT:

Pomyślałem, że sprawdzanie ważny dowód w sterowniku było złe, bo to zawsze załadować widok przynajmniej na ułamek sekundy. Szukałem pewnego rodzaju oprogramowania pośredniczącego, ale potem zapomniałem, że już korzystam z pakietu angular-permission, który działa jak front-end middleware.

Zdefiniowałem rolę isTokenValid i ustawiłem ją tak, że automatycznie wywołuje funkcję w authService, którą mam, i otrzymuje odpowiedź z mojego API na podstawie ważności tokena. Jeśli się powiedzie, rola pozwala użytkownikowi na wejście w stan. W przeciwnym razie przekierowuje do stanu reset. Zapobiega to wyświetlaniu widoku przez ułamek sekundy. Działa bardzo podobnie do oprogramowania pośredniego Laravel.

Jedynym problemem jest to, że dzieje się to z przodu, każdy haker może ominąć to, ale to jest w porządku, ponieważ kod po stronie serwera jest nadal dostępny, więc nawet jeśli dostęp do widoku nie może nic zrobić z wprowadzonymi hasłami powoduje, że token jest nadal nieprawidłowy i musi pasować do konkretnego użytkownika.

Inną poprawą byłoby znalezienie sposobu na zablokowanie widoku, nawet bez implementacji front-end middleware. Może zaktualizuję to ponownie, jeśli znajdę sposób na zrobienie tego.

Realizacja

Rola:

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

A państwo:

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

Nadzieja pomaga ktoś z tym samym problemem.

+0

Jest to przydatne pytanie i ilustracja techniki dla każdego, kto rozwija się z Laravel i Angular. Dzięki za publikację. – delatbabel