Смена пароля в «Ajax системе регистрации/авторизации»

13 комментариев

Обнаружив статью об Ajax системе авторизации, я внедрил ее в свой проект, все работает просто отлично, за что отдельное спасибо автору этих скриптов.

Но немного поковырявшись в системе, столкнулся с тем, что данное приложение не позволяет менять пароль и решил попробовать это исправить.

Не судите строго, код получился довольно грязным и непрофессиональным (т.к. к программированию я имею весьма косвенное отношение), но рабочим, кстати, комментариев в коду это тоже касается ;)

Заранее благодарю товарищей, которые обнаружат баги или предложат оптимизацию кода. Итак, поехали.

Что будем менять и что дополнять?

Имена файлов я не изменял, так что все названия приведены в соответсвии с исходным проектом. Для добавления возможности смены пароля потребуются изменения в следующих файлах:

  • ajax.php
  • Auth.class.php
  • ajax-form.js

А также создадим страничку для смены пароля: return.php.

Теперь по порядку.

Перво-наперво создадим return.php, где и будет происходить смена пароля.

<?php

if (!empty($_COOKIE['sid'])) {
    // check session id in cookies
    session_id($_COOKIE['sid']);
}
session_start();
require_once './classes/Auth.class.php';

?><!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Password change</title>
    <meta name="viewport" content="width=device-width, initial-scale=0.7">
    <link rel="stylesheet" href="./vendor/bootstrap/css/bootstrap.min.css">
    <link rel="stylesheet" href="./css/style.css">
  </head>
  <body>
    <div class="container">

      <?php if (Auth\User::isAuthorized()): ?>

      <h1>Your are already logined!</h1>

      <form class="ajax" method="post" action="./ajax.php">
          <input type="hidden" name="act" value="logout">
          <div class="form-actions">
              <button class="btn btn-large btn-primary" type="submit">Logout</button>
          </div>
      </form>

      <?php else: ?>

      <form class="form-signin ajax" method="post" action="./ajax.php">
        <div class="main-error alert alert-error hide"></div>
       <h2 class="form-signin-heading">Password Change</h2>
        <input name="username" type="text" class="input-block-level" placeholder="Username" autofocus>
        <p>Enter Your old password or Security code from back side of controller</p>
        <input name="old_password" type="password" class="input-block-level" placeholder="Old Password">
              <input name="new_password" type="password" class="input-block-level" placeholder="New Password">
        <input name="new_password2" type="password" class="input-block-level" placeholder="Confirm new password">
        <input type="hidden" name="act" value="change_password">
        <button class="btn btn-large btn-primary" type="submit">Change password</button>
        <div class="alert alert-info" style="margin-top:15px;">
            <p>Already have account? <a href="/">Sign In.</a>
        </div>
      </form>

      <?php endif; ?>
    </div> <!-- /container -->

    <script src="./vendor/jquery-2.0.3.min.js"></script>
    <script src="./vendor/bootstrap/js/bootstrap.min.js"></script>
    <script src="./js/ajax-form.js"></script>
  </body>
</html>

Тут особо нечего разбирать, форма аналогична register.php. Единственное отличие — это поле old_password из которого мы будем брать старый пароль и проверять его.

Теперь требуется пошаманить с Auth.class.php, a точнее обьявить новую public function change_password.

public function change_password($username, $password)
{
    $user_exists = $this->getSalt($username);
    if (!$user_exists) {
        throw new \Exception("User doesn't exist: " . $username, 1);
    }

    $query = "update users set password = :password where username = :username";
    $salt = $this->getSalt($username);
    $hashes = $this->passwordHash($password, $salt);
    $sth = $this->db->prepare($query);

    $this->db->beginTransaction();
    $result = $sth->execute(  
        array( 
            ':username' => $username,
            ':password' => $hashes['hash'],
        )
    );

    $this->db->commit(); 
    $this->user = $sth->fetch();

    if (!$result) {
        $info = $sth->errorInfo();
        printf("Database w t f error %d %s", $info[1], $info[2]);
        die();
    } 
    return $result;     
}

Сначала проверяем, есть ли такой пользователь, если нет то выбрасываем исключение, если есть то отправляем запрос на обновление базы данных, предварительно посолив новый пароль старой солью. Если при выполнении запроса происходит ошибка, печатаем соответствуюее сообщение и завершаем работу скрипта.

Теперь двигаемся в ajax.php

В самом начале файла находим public $actions и добавляем "change_password" => "change_password",.

public $actions = array(
    "login" => "login",
    "logout" => "logout",
    "register" => "register",
    "change_password" => "change_password",
);

Теперь надо создать обработчик. Внутри class AuthorizationAjaxRequest extends AjaxRequest создадим public function change_password().

public function change_password()
{
    if ($_SERVER["REQUEST_METHOD"] !== "POST") {
        //  Method Not Allowed
        http_response_code(405);
        header("Allow: POST");
        $this->setFieldError("main", "Method Not Allowed");
        return;
    }
    setcookie("sid", "");

    $username = $this->getRequestParam("username");
    $old_password = $this->getRequestParam("old_password");
    $new_password = $this->getRequestParam("new_password");  
    $new_password2 = $this->getRequestParam("new_password2");

    if (empty($username)) {
        $this->setFieldError("username", "Enter the username");
        return;
    }

    if (empty($old_password))  {
        $this->setFieldError("old_password", "Enter old  password");
        return;
    }

    $user = new Auth\User();
    $pass_check = $user->authorize($username, $old_password);
    if (!$pass_check) {
        $this->setFieldError("password", "Invalid old password");
        return;
    }

    if (empty($new_password)) {
        $this->setFieldError("new_password", "type new password");
        return;
    }

    if (empty($new_password2)) {
        $this->setFieldError("new_password2", "Confirm the password");
        return;
    }

    if ($new_password !== $new_password2) {
        $this->setFieldError("new_password2", "Confirm password is not match");
        return;
    }

    try {   
        $change_password = $user->change_password($username, $new_password);      
    } catch (\Exception $e) {
        $this->setFieldError("username", $e->getMessage());
        return;
    }
    $user->authorize($username, $new_password);

    $this->message = sprintf("Hello, %s! Password had been successfully changed.", $username);
    $this->setResponse("redirect", "/");
    $this->status = "ok";
}

Проверяем заполнение всех полей, а так же пытаемся залогиниться по старому паролю, если все ок, то пытаемся поменять пароль и заново залогиниться уже по новому паролю.

Теперь осталось только немного подшаманить ajax-form.js, а именно добавить в callbacks:

change_password: function ($form, data) {
    if (data.status === 'ok') {
        if (data.data && data.data.redirect) {
            window.location.href = data.data.redirect;
        }
    }
}

На этом, в принципе, всё. После всех этих махинаций должно работать. Буду рад конструктивной критике и советам по оптимизации кода. Если нашли ошибку в коде или тексте статьи — пожалуйста напишите о ней в комментариях.

Автор: Rimash

Комментарии к статье: 13

Подождите, загружаются комментарии...

Возможность комментировать эту статью отключена автором. Возможно, во всем виновата её провокационная тематика или большое обилие флейма от предыдущих комментаторов.

Если у вас есть вопросы по содержанию статьи, рекомендуем вам обратиться за помощью на наш форум.