2017-01-25 2 views
5

Я пишу тест, который гарантирует, что функция сброса пароля моего приложения будет работать. Система сброса пароля была создана с помощью команды php artisan make:auth. Чтобы выполнить пробный проход, мне нужно автоматизировать запрос GET на /password/reset/{$token}, где $token - это значение, хранящееся в таблице password_resets. Laravel хранит лексемы, как это:Decrypt Laravel Password Reset Token

$2y$10$9grKb3c6.Toiv0kjUWbCUeT8Q8D.Fg2gZ/xDLGQUAkmdyHigmRkNW

но когда Laravel отправляет сообщение электронной почты для сброса пароля для пользователя, маркер сброса выглядит в письме:

382aa64567ecd05a774c2e4ebb199d3340a1424300707053354c749c10487594.

Мой запрос GET на /password/reset/$2y$10$9grKb3c6.Toiv0kjUWbCUeT8Q8D.Fg2gZ/xDLGQUAkmdyHigmRkNW не работает из-за косой черты в марке сброса. (Сразу после «g2gZ»)

Я пробовал использовать вспомогательную функцию decrypt(), но не повезло.

Как я могу конвертировать ток сброса пароля Я вытаскиваю из таблицы password_resets в соответствии с тем, что Laravel отправляет пользователю?

Не уверен, что это актуально, но я обновил свое приложение с 5.3 до 5.4.

ответ

6

Вы можете получить маркер от закрытия используется для дополнительной проверки прошли к методу assertSentTo уведомления, поскольку $token является общедоступным стандартом уведомления ResetPassword.

Notification::fake(); 

$this->postJson('api/user/reset', ['email' => $user->email]) 
    ->assertStatus(200); 

$token = ''; 

Notification::assertSentTo(
    $this->user, 
    ResetPassword::class, 
    function ($notification, $channels) use (&$token) { 
     $token = $notification->token; 

     return true; 
    }); 

$this->postJson('api/user/resetting', [ 
    'email' => $user->email, 
    'token' => $token, 
    'password' => '87538753', 
    'password_confirmation' => '87538753' 
]) 
    ->assertStatus(200); 
+0

Это сладкое решение, THX для обмена! – superfly

+0

@pinguinjkeke не могли бы вы объяснить, почему вы используете Notification :: fake(); почему мы используем оповещение здесь ...? – usama

+0

Каналы уведомлений @usama Laravel можно также использовать для отправки Mailables. Начиная с некоторого времени стандартное письмо сброса пароля отправляется как уведомление. Я использую '' 'Notification :: fake()' '' для целей тестирования, и вызывать фальшивые уведомления не будут отправлены реальными, просто сохраните информацию об этом внутри тестов. Проверьте эту ссылку: https://laravel.com/docs/5.4/mocking#notification-fake – pinguinjkeke

2

Токен, хранящийся в таблице password_resets, хэширован как обычный пароль, поэтому вы не можете отменить его, чтобы получить исходный токен.

Я предлагаю вам использовать log mail driver при выполнении тестов. Затем электронное письмо с сбросом пароля будет напечатано в обычном тексте в журнале laravel, и вы сможете извлечь из него токен.

+1

Хорошая идея использовать драйвер журнала. объедините это с помощью простого разделителя preg_match, и это будет довольно быстро и легко захватить. –

+0

Хорошо, спасибо за помощь ребятам. Мне нужно захватить токен ** перед ** шифрованием для моего теста. Похоже, что захватить его из файла журнала будет путь. –

+0

@DenisPriebe У меня такая же проблема, но я не совсем понял, как вы ее решили. Вы реализовали решение? Можете ли вы добавить его к нашему? Было бы неплохо! Tx! –

1

Я не думаю, что вы можете, хэш, который был сохранен, является зашифрованным значением хэша sha256 случайного 40-значного числа. что означает, что он не может быть обратимым только в одном направлении.

1

Для проверки функциональности сброса пароля я заменил сгенерированный токен из таблицы password_reset на новый.

Сброс маркера создается с createTokenRepository() методом - laravel/framework/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php

Для хэширования созданный маркер, Laravel использует make() метод - laravel/framework/src/Illuminate/Hashing/BcryptHasher.php

public function test_it_should_reset_the_password() 
{ 

    Mail::fake(); 

    $user = factory(App\User::class)->create(); 

    $response = $this->json('POST', 'api/password/email', 
        [ 
         'email' => $user->email 
        ]); 
    $response->assertStatus(202); 

    Mail::hasSent($user, ResetPassword::class); 

    // Since we don't know the emailed token from 
    // the previous JSON call, we're 
    // gonna replace the token with a new one 
    $token = hash_hmac('sha256', Str::random(40), $user); 
    DB::table('password_resets') 
      ->where('email', $user->email) 
      ->update([ 
       'token' => password_hash($token, PASSWORD_BCRYPT, ['cost' => '10']) 
      ]); 

    $response = $this->json('POST', 'api/password/reset', [ 
        'email'     => $user->email, 
        'password'    => 'new_user_password', 
        'password_confirmation' => 'new_user_password', 
        'token'     => $token 
       ]); 
    $response->assertStatus(202); 

    $response = $this->json('POST', 'api/login', 
        [ 
         'email' => $user->email, 
         'password' => 'new_user_password' 
        ]); 
    $response->assertStatus(202); 
    // check for JWT token 
    $response->assertJson(['token' => true]); 

}