LoginSignup
3
4

More than 5 years have passed since last update.

Zxcvbn + RxBinding で入力されたパスワードの強度をチェックする

Last updated at Posted at 2017-09-18

passcheck.gif

EditTextに入力されたパスワードを検知して強度をチェックするという内容が、こちらの記事で紹介されていたので試してみました。
RxBindingがRxJava2に対応していたので、本記事ではそちらを使用しています。

ライブラリを準備

以下のライブラリを使用します。

app/build.gradle
    compile "io.reactivex.rxjava2:rxjava:2.1.3"
    compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
    compile 'com.nulab-inc:zxcvbn:1.2.3'

※上記に記載していませんが、retrolambdaを使ってラムダ式で記述します。

zxcvbn4jについて

DropBoxが公開しているパスワード強度チェックライブラリzxcvbnのJava移植版で、Nulab社から公開されています。

READMEに記載の通り、使い方も非常に簡単で、measure メソッドに文字列を渡すと結果を得られます。

Zxcvbn zxcvbn = new Zxcvbn();
Strength strength = zxcvbn.measure("This is password");

レイアウトを作成

パスワードを入力するEditTextを追加します。

<EditText
    android:id="@+id/password"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="textPassword"
    android:maxLines="1" />

入力されたパスワードに応じて、結果を表示するViewを追加します。
zxcvbnのスコアは、0〜4の整数で返ってくるので、android:max="4"としています。
弱いパスワード [0] <-----> [4] 強いパスワード

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ProgressBar
        android:id="@+id/password_strength_bar"
        style="?android:progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:max="4" />

    <TextView
        android:id="@+id/password_strength_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="4"
        android:gravity="center"
        android:minLines="2" />

</LinearLayout>

入力を検知して、結果を更新する。

RxBindingを使ってEditTextの内容変更を通知、zxcvbnでスコアを測定して、結果を他のViewに渡します。

SignUpActivity.java
Zxcvbn zxcvbn = new Zxcvbn();
// EditTextをObservable化
RxTextView.textChanges(mPasswordEditText)
     // スコアの測定は計算スレッドで行う
        .observeOn(Schedulers.computation())
        .map(CharSequence::toString)
        .map(zxcvbn::measure)
     // 0〜4の整数でスコアを取得
        .map(Strength::getScore)
         // メインスレッドで他のViewに渡す
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(score -> {
            mStrengthProgressBar.setProgress(score);
            mStrengthTextView.setText(PASSWORD_STRENGTH_MESSAGES[score]);
        });

ここでは、以下のような配列を用意して、スコアに応じたテキストをTextViewに渡しています。

private static final String[] PASSWORD_STRENGTH_MESSAGES = new String[] {
        "Weak", "Fair", "Good", "Strong", "Very Strong"
};

元の記事では、 MissingBackpressureExceptionの回避のために.onBackpressureLatest() を指定していましたが、RxJava2ではBackPressureがFlowableのみの機能となりました。
Flowableはサーバサイドなどで大量のデータを扱う場合を想定しているようで、GUIイベント程度の少量のデータであれば、オーバーヘッドの少ないObservableを使う方が良いとのことなので、削っています。
https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#observable-and-flowable
入力の度に無駄な処理を走らせたくないのであれば、Throttlingで入力後に間隔が空いたら通知するようにすれば良さそう。

その他

strength.getScore() ではなく、 strength.getFeedback()とすると、そのパスワードに対してのフィードバックが得られます。
ローカライズにも対応していて getFeedback().getSuggestions(Locale.JAPAN)のようにすると上記のGIFのように日本語で修正の提案のメッセージが得られます。便利!

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4