序章

パスワードは、ほとんどのWebアプリケーションでユーザー認証に一般的に使用されます。 このため、パスワードを安全な方法で保存することが重要です。 長年にわたり、データベースに保存されているパスワードの実際の表現を隠すために、一方向パスワードハッシュなどの手法が採用されてきました。

パスワードハッシュはパスワードを保護するための大きな一歩ですが、ユーザーは依然としてパスワードのセキュリティに大きな課題を抱えています。ブルートフォース攻撃のため、パスワードとして一般的な単語を使用するユーザーは、ハッシュの努力を無駄にします。 ]は、そのようなパスワードをすばやく解読できます。

これに対処するために、今日の多くのWebアプリケーションは、パスワードの最小長を確保するか、パスワードに英数字と記号を組み合わせることにより、強力なパスワードを持つユーザーを要求しています。 パスワード強度を測定するために、Dropboxは、パスワードクラッカーに触発された現実的なパスワード強度推定器のアルゴリズムを開発しました。 このアルゴリズムは、zxcvbnというJavaScriptライブラリにパッケージ化されています。 さらに、パッケージには、一般的に使用される英語の単語、名前、およびパスワードの辞書が含まれています。

このチュートリアルでは、React JavaScriptフレームワークを使用して、氏名、電子メール、およびパスワードのフィールドを持つフォームを作成します。 軽量のフォーム検証を実行し、 zxcvbn ライブラリを使用して、視覚的なフィードバックを提供しながら、フォーム内のパスワードの強度を推定します。

このチュートリアルの終わりまでに作成するもののこのCodeSandboxデモをチェックしてください。

前提条件

開始する前に、システムにNodeの最新バージョンがインストールされていることを確認してください。

このチュートリアルに従うには、次のものが必要です。

  • マシンにインストールされているNodeの最新バージョン。 これをインストールする方法の詳細については、 How To InstallNode.jsコレクションからディストリビューションを選択してください。
  • yarn をインストールして、すべての NPM スクリプトを実行し、プロジェクトの依存関係をインストールします。 このYarnインストールガイドに従って、システムにyarnをインストールできます。

ステップ1—アプリケーションのセットアップ

このチュートリアルでは、 create-react-app パッケージを使用して、新しいReactアプリケーションを生成します。 create-react-appをまだインストールしていない場合は、次のコマンドを実行してシステムにインストールします。

  1. npm install -g create-react-app

インストールが完了したら、次のコマンドを使用して新しいReactアプリケーションを起動します。

  1. create-react-app react-password-strength

このコマンドはreact-password-strengthという名前を付けますが、好きな名前を付けることができます。

注: npmバージョン5.2以降を使用している場合は、追加のnpxバイナリが付属しています。 npxバイナリを使用すると、システムにcreate-react-appをグローバルにインストールする必要はありません。 次のコマンドで新しいReactアプリケーションを開始できます:npx create-react-app react-password-strength

次に、アプリケーションに必要な依存関係をインストールします。 次のコマンドを実行して、必要な依存関係をインストールします。

  1. yarn add zxcvbn isemail prop-types node-sass bootstrap

このコマンドは、次の依存関係をインストールします。

  • zxcvbn-前述のパスワード強度推定ライブラリ。
  • isemail-電子メール検証ライブラリ。
  • prop-types-コンポーネントに渡される意図されたタイプのプロパティのランタイムチェック。
  • node-sass-SassファイルをCSSにコンパイルするために使用されます。

お気づきかもしれませんが、デフォルトのスタイルを取得するために、アプリケーションの依存関係としてbootstrapパッケージをインストールしました。 アプリケーションにブートストラップを含めるには、src/index.jsファイルを編集し、他のすべてのimportステートメントの前に次の行を追加します。

src / index.js
import 'bootstrap/dist/css/bootstrap.min.css';

最後に、アプリケーションを開始します。

  1. yarn start

これでアプリケーションが起動し、開発を開始できます。 ライブリロード機能を備えたブラウザタブが開いていることに注意してください。 これにより、開発時にアプリケーションの変更と同期が保たれます。

この時点で、アプリケーションビューは次のスクリーンショットのようになります。

Initial View

ステップ2—コンポーネントの構築

このアプリケーションは、氏名、電子メール、およびパスワードのフォームを使用します。 また、フィールドで軽量のフォーム検証を実行します。 このステップでは、次のReactコンポーネントを作成します。

  • FormField-フォーム入力フィールドをその属性と変更イベントハンドラーでラップします。

  • EmailField-電子メールFormFieldをラップし、それに電子メール検証ロジックを追加します。

  • PasswordField-パスワードFormFieldをラップし、パスワード検証ロジックを追加します。 また、パスワード強度メーターとその他の視覚的な手がかりをフィールドに添付します。

  • JoinForm-フォームフィールドを格納する架空のJoinSupportTeamフォーム。

アプリケーションのsrcディレクトリ内にcomponentsディレクトリを作成して、すべてのコンポーネントを格納します。

FormFieldコンポーネント

src/componentsディレクトリに新しいファイルFormField.jsを作成し、それに次のコードスニペットを追加します。

src / components / FormField.js
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';

class FormField extends Component {

  // initialize state
  state = { value: '', dirty: false, errors: [] }

  hasChanged = e => {
    e.preventDefault();

    // destructure props - assign default dummy functions to validator and onStateChanged props
    const { label, required = false, validator = f => f, onStateChanged = f => f } = this.props;

    const value = e.target.value;
    const isEmpty = value.length === 0;
    const requiredMissing = this.state.dirty && required && isEmpty;

    let errors = [];

    if (requiredMissing) {
      // if required and is empty, add required error to state
      errors = [ ...errors, `${label} is required` ];
    } else if ('function' === typeof validator) {
      try {
        validator(value);
      } catch (e) {
        // if validator throws error, add validation error to state
        errors = [ ...errors, e.message ];
      }
    }

    // update state and call the onStateChanged callback fn after the update
    // dirty is only changed to true and remains true on and after the first state update
    this.setState(({ dirty = false }) => ({ value, errors, dirty: !dirty || dirty }), () => onStateChanged(this.state));
  }

  render() {
    const { value, dirty, errors } = this.state;
    const { type, label, fieldId, placeholder, children } = this.props;

    const hasErrors = errors.length > 0;
    const controlClass = ['form-control', dirty ? hasErrors ? 'is-invalid' : 'is-valid' : '' ].join(' ').trim();

    return (
      <Fragment>
        <div className="form-group px-3 pb-2">
          <div className="d-flex flex-row justify-content-between align-items-center">
            <label htmlFor={fieldId} className="control-label">{label}</label>
            {/** Render the first error if there are any errors **/}
            { hasErrors && <div className="error form-hint font-weight-bold text-right m-0 mb-2">{ errors[0] }</div> }
          </div>
          {/** Render the children nodes passed to component **/}
          {children}
          <input type={type} className={controlClass} id={fieldId} placeholder={placeholder} value={value} onChange={this.hasChanged} />
        </div>
      </Fragment>
    );
  }

}

FormField.propTypes = {
  type: PropTypes.oneOf(["text", "password"]).isRequired,
  label: PropTypes.string.isRequired,
  fieldId: PropTypes.string.isRequired,
  placeholder: PropTypes.string.isRequired,
  required: PropTypes.bool,
  children: PropTypes.node,
  validator: PropTypes.func,
  onStateChanged: PropTypes.func
};

export default FormField;

このコンポーネントでは、いくつかの作業を行っています。 少し分解してみましょう。

入力状態:最初に、フォームフィールドコンポーネントのstateを初期化して、入力フィールドの現在のvaluedirtyのステータスを追跡します。フィールド、および既存の検証errors。 フィールドは、その値が最初に変更されてダーティのままである瞬間にダーティになります。

入力変更の処理:次に、hasChanged(e)イベントハンドラーを追加して、入力が変更されるたびに状態valueを現在の入力値に更新しました。 ハンドラーでは、フィールドのdirty状態も解決します。 フィールドが小道具に基づいてrequiredフィールドであるかどうかを確認し、値が空の場合は状態errors配列に検証エラーを追加します。

ただし、フィールドが必須フィールドではない場合、または必須であるが空ではない場合は、オプションのvalidatorプロップで渡された検証関数に委任し、現在の入力値で呼び出し、スローされた検証エラーを追加します状態errors配列に(エラーがある場合)。

最後に、状態を更新し、更新後に呼び出されるコールバック関数を渡します。 コールバック関数は、オプションのonStateChanged propで渡された関数を呼び出し、更新された状態を引数として渡します。 これは、コンポーネントの外部に状態変化を伝播するのに便利です。

レンダリングと小道具:ここでは、入力フィールドとそのラベルをレンダリングしています。 また、状態errors配列の最初のエラーを条件付きでレンダリングします(エラーがある場合)。 Bootstrapの組み込みクラスを使用して、検証ステータスを表示するように入力フィールドのクラスを動的に設定する方法に注目してください。 また、コンポーネントに含まれるすべての子ノードをレンダリングします。

コンポーネントのpropTypesに見られるように、このコンポーネントに必要な小道具はtype'text'または'password')、label、[X127X ]