パスワードをお忘れの方ページで登録済みのメールアドレスを入れると、パスワード変更ページへ遷移し、パスワードの再発行ができる機能を作成しました。
こんにちは。Webコーダーのはるです。
現在、所属している「もりけん塾」でJavaScriptのハンズオン課題 に取り組み、レビューをいただいています。
今日は、課題28 についてアウトプットをしていきます。
(前回までのアウトプットは、こちらです。)
実装する過程で学んだことを、学習ノートとして記録していきます。
認識の間違えている箇所がありましたら、お問い合わせからご指摘いただけるとうれしいです。
JavaScript課題28の仕様
(もりけん先生のJavaScriptハンズオン課題より)
JavaScript課題28の記録
会員登録された内容をローカルストレージに保存
この課題から以下の仕様が追加されたので、まずこの部分を修正していきました。
– ログイン時は、入力値とローカルストレージの値を照合する
※ローカルストレージは、セキュリティの観点から仕様するべきではないですが、あくまで学習のために使用しています。( ref: ローカルストレージは使うな )
会員登録の時
会員登録でsubmitボタンを押すと、inputに入力された情報がローカルストレージに登録されます。
まず、inputされたデータを取得してオブジェクトに格納。
submitButton.addEventListener("click", (e) => {
e.preventDefault();
const inputsData = {
name: nameOfInput.value,
email: emailOfInput.value,
password: passwordOfInput.value
};
const registeredData = JSON.parse(localStorage.getItem("registeredData"));
if (registeredData && inputsData.email === registeredData.email) {
submitButton.disabled = true;
showErrorMessage(e.target);
return;
}
メールアドレスが未登録だった場合は、入力値を”registerdData”としてローカルストレージに保存。
localStorage.setItem("registeredData", JSON.stringify(inputsData));
window.location.href = "./register-done.html";
});
ログインの時
ログインするときは、入力値がローカルストレージに登録されている”registeredData”の値と照合します。
照合は、ローカルストレージ(仮想サーバーの代わり)との通信をする想定なので、promise を使用しました。
const checkToRegistered = () => {
return new Promise((resolve, reject) => {
const inputsValues = {
userId: userIdOfInput.value,
password: passwordOfInput.value
}
const registeredData = JSON.parse(localStorage.getItem("registeredData"));
if ((inputsValues.userId === registeredData.name || inputsValues.userId === registeredData.email) && (inputsValues.password === registeredData.password)) {
resolve({ token: chance.apple_token(), ok: true, code: 200 });
} else {
reject({ ok: false, code: 401 });
}
})
}
照合の条件式、
- 入力ユーザーIDと登録ユーザー名 or 登録メールアドレス が等しい
かつ
- 入力パスワードと登録メールアドレス が等しい
が満たされれば、tokenが発行されます。
/* この部分 */
if ((inputsValues.userId === registeredData.name || inputsValues.userId === registeredData.email) && (inputsValues.password === registeredData.password)) {
resolve({ token: chance.apple_token(), ok: true, code: 200 });
} else {
reject({ ok: false, code: 401 });
}
}
照合後、resolve, rejectで渡されるオブジェクトが 変数resultに格納されます。
const tryToLogin = async() => {
let result;
try {
result = await checkToRegistered();
localStorage.setItem("token", result.token);
} catch(rejectObj) {
result = rejectObj;
} finally {
window.location.href = result.token ? "./index.html" : "./notautherize.html";
}
}
finallyで、渡ってきたオブジェクトに “token” の値があればログインができる仕組みです。
これらは、submitボタンが押されたときに実行されます。
submitButton.addEventListener("click", tryToLogin);
パスワードをお忘れの方へページの作成
新しいページを作成。
会員登録済みのメールアドレスを入力してSubmitボタンを押すと、パスワード変更のページへ遷移するようにしました。
ここでもpromiseを使用して、emailOfInput.value === registeredData.email
の場合はtokenを発行しました。
const checkToRegistered = () => {
return new Promise((resolve, reject) => {
const registeredData = JSON.parse(localStorage.getItem("registeredData"));
if (emailOfInput.value === registeredData.email) {
resolve({ token: chance.apple_token(), ok: true, code: 200 });
} else {
reject({ ok: false, code: 401 });
}
})
}
localStorage.setItem("passwordReissueToken", result.token);
const tryToSubmit = async() => {
let result;
try {
result = await checkToRegistered();
localStorage.setItem("passwordReissueToken", result.token);
} catch(rejectObj) {
result = rejectObj;
submitButton.nextElementSibling.textContent = "一致するアカウントが見つかりませんでした";
submitButton.disabled = true;
return;
}
const urlParameter = `?token=${result.token}`;
window.location.href = `./register/password.html${urlParameter}`;
}
}
メールアドレスが合っていた場合に発行されたtokenは、URLパラメータに埋め込まれます。
/* この部分 */
const urlParameter = `?token=${result.token}`;
window.location.href = `./register/password.html${urlParameter}`;
tryToSubmit関数 は、submitボタンを押したときに実行されます。
submitButton.addEventListener("click", tryToSubmit);
パスワード変更ページの作成
このようなぺージを作成しました。
URLSearchParams
このページに遷移してきた時、
- URLパラメータのtokenとローカルストレージのtokenが等しいか
確認をして、間違っていた場合は権限なしページへ移動するようにします。
(これは、ローカルストレージがサーバー側の役割をしている想定です。)
const urlParameter = Object.fromEntries(new URLSearchParams(window.location.search));
const currentPageToken = urlParameter.token;
const registeredToken = localStorage.getItem("passwordReissueToken");
if(currentPageToken !== registeredToken) window.location.href = "./../notautherize.html";
URLパラメータをJavaScriptで扱うときは、URLSearchParamsを使用すると簡単に扱うことができます。
URLSearchParams() コンストラクターは、新しい URLSearchParams オブジェクトを作成して返します。 先頭の ‘?’ 文字は無視されます。(MDNより)
URLSearchParams オブジェクトをObject.FromEntries()することで、URLパラメータのキーと値をオブジェクトに変換することができます。
const urlParameter = Object.fromEntries(new URLSearchParams(window.location.search));
// output
// {token: '8474a1996c12bd1d1bb68dac4983e8e505ab9596005b5303f6e42904a118b465'}
バリデーション
新規パスワード入力と、確認のためのパスワード入力の2つのinputがあり、
- 空欄でないか
- 8文字以上の大小英数字か
- 2つのinputが同じ値か
をチェックしました。
formElements.forEach(element => {
element.classList.add("invalid");
element.addEventListener("blur", () => {
checkFormValidityInBlur(submitButton, element);
if (document.getElementsByClassName("invalid").length === 0) {
showErrorMessageInNotMatchInputsValues();
checkFormValidityToEnableSubmitButton();
}
});
});
formElementsは、2つのinputが配列化されています。
それぞれのinputがblurされると、modulesのバリデーション(空欄・8文字以上大小英数字チェック)が走ります。
checkFormValidityInBlur(submitButton, element);
バリデーションが通っていないinputに付与しているinvalidクラスがなければ、2つのinputの値が等しいかのチェックが走ります。
if (document.getElementsByClassName("invalid").length === 0) {
showErrorMessageInNotMatchInputsValues();
checkFormValidityToEnableSubmitButton();
}
/* それぞれの関数 */
const showErrorMessageInNotMatchInputsValues = () => errorOfConfirmPassword.textContent = passwordOfInput.value !== confirmPasswordOfInput.value ? "上記のpasswordと異なります。もう一度入力してください。": "";
const checkFormValidityToEnableSubmitButton = () => submitButton.disabled = passwordOfInput.value !== confirmPasswordOfInput.value;
パスワードを表示・非表示させる
仕様にはありませんでしたが、ユーザーがパスワードを表示・非表示の切り替えをできるようにしました。2つのinputが合っているかのチェックにも合ったほうがわかりやすいと思ったからです。
目のマークを押すと、togglePasswordDisplay関数が実行されます。
eyeIcons.forEach(icon => {
icon.addEventListener("click", (e) => togglePasswordDisplay(e.target))
})
const togglePasswordDisplay = target => {
const selectedInput = target.nextElementSibling;
selectedInput.type = selectedInput.type === "password" ? "text" : "password";
target.classList.toggle("is-open");
}
// 修正前のif文
if (selectedInput.type === "password"){
selectedInput.type = "text";
target.classList.add("is-open");
} else {
selectedInput.type = "password";
target.classList.remove("is-open");
}
パスワード変更
パスワード変更の関数を作成しました。
流れは、
① ローカルストレージの “registeredData”を取得して、オブジェクトに変換
② オブジェクト内のpasswordキーの値だけ、input入力値に変更
③ 変更済みのオブジェクトをローカルストレージの”regiseredData”に上書き保存
const changePassword = () => {
const passwordValue = passwordOfInput.value;
const userData = JSON.parse(localStorage.getItem("registeredData"));
userData.password = passwordValue;
localStorage.setItem("registeredData", JSON.stringify(userData));
}
submitButton.addEventListener("click", () => {
changePassword();
const token = chance.apple_token();
const newUrlParameter = `?token=${token}`;
localStorage.setItem("passwordReissueToken", token);
window.location.href = `./passworddone.html${newUrlParameter}`;
});
それに伴って、新しいpasswordReissueToken
が発行されて、パスワード変更完了ページへ遷移します。
パスワード変更完了ページを作成
このようなぺージを作成しました。
このページに遷移してきたとき、パスワード変更ページと同様に、ローカルストレージのtokenとURLパラメータのtokenが等しいかどうかの確認をします。
const urlParameter = Object.fromEntries(new URLSearchParams(window.location.search));
const currentPageToken = urlParameter.token;
const registeredToken = localStorage.getItem("passwordReissueToken");
if(currentPageToken !== registeredToken) window.location.href = "./../notautherize.html";
localStorage.removeItem("passwordReissueToken");
間違っていた場合は、権限なしページへ遷移。
合っていた場合は、passwordReissueToken
を削除するようにしました。
この後は、ログインページに戻り新しいパスワードでログインできるようになります。
今回のコード
Sign Upから会員登録をした後、「パスワードをお忘れの方はこちら」から実際にパスワード変更手続きが可能です。
//
学習に使用している本は、JavaScript本格入門・独習JavaScriptです。
あとがき
もりけん先生(@terrace_tec)、さえさん(@sae_prog)、まいさん(@mai2022web)、ちひろさん(@chihiro7029) お忙しい中レビューいただきありがとうございました!
今回も、細かなバリデーションの動作確認や、違和感を感じた部分をご指摘いただき、Refactorを重ねてより良いコードになりました。
一部仕様を満たせていない旨ご指摘もあり、反省です。
また、関数名と変数名はいまだに命名がうまくできていないと知りました。
いかに短くシンプルな命名で、コード内容を的確に表すかを考えて次に活かしたいと思います。
今日は以上です。
//
【もりけん塾で勉強しています】
もりけん先生(@terrace_tec)のHPはこちら
元々、finallyを使用して if(!result.token) 条件下は、パスワード変更ページへ遷移するようにしていましたが、catch節の場合はreturnで抜けて、finallyは使わない方がわかりやすいコードになると教えていただきました。