SpringとJPAに基づくWebアプリケーション開発#32パスワード修正

44378 ワード

SpringとJPAに基づくWebアプリケーション開発#32パスワード修正
これらはインフラストラクチャ、Spring、JPAベースのWebアプリケーション開発のコースに基づいて作成されています.

要約は、学習コース、要約ソースのタグ付け、ブログまたはドキュメント形式で公開できるようにする原則の下で公開されます.出典は前述の通り、インフラストラクチャ、Spring、JPAベースのWebアプリケーション開発.
私が勉強しているソースコードはhttps://github.com/n00nietzsche/jakestudy_webappにアップロードされます.私は伝言ごとに講義のどの部分を記録します.

パスワードの変更

  • パスワードラベル
  • を有効にする
  • 新しいパスワードと新しいパスワードの確認値は一致する必要があります.
  • 暗号化
  • の間の最小8文字から最大50文字数は
  • です.
  • ユーザー情報の変更
  • サービスに委任し、トランザクション内で処理する必要があります.
  • ステータスが
  • またはDetachedのオブジェクトを変更し、Repository.save()を呼び出してステータス変更を適用できます.
  • PasswordFormクラスの作成

    @Data
    public class PasswordForm {
        @Length(min = 8, max = 50)
        private String newPassword;
        @Length(min = 8, max = 50)
        private String newPasswordConfirm;
    }

    PasswordFormValidatorクラスの作成

    @Component
    public class PasswordFormValidator implements Validator {
        @Override
        public boolean supports(Class<?> aClass) {
            // 매개변수로 해당 클래스/인터페이스를 상속/구현한 클래스가 들어온건지 확인
            // Object 의 instanceOf 와 비슷하다.
            return PasswordForm.class.isAssignableFrom(aClass);
        }
    
        @Override
        public void validate(Object o, Errors errors) {
            PasswordForm passwordForm = (PasswordForm) o;
            if(!passwordForm.getNewPassword().equals(passwordForm.getNewPasswordConfirm())) {
                errors.rejectValue("newPassword","wrong.value", "입력한 새 패스워드가 일치하지 않습니다.");
            }
        }
    }

    PasswordFormValidatorをSettingsコントローラに適用する

    ...
    public class SettingsController {
        private final AccountService accountService;
        private final PasswordFormValidator passwordFormValidator;
    ...
    
    @InitBinder("passwordForm")
        // WebDataBinder 는 WebRequestParameters 를 받아서 Java Beans Object 형태로 변환해주는 역할을 한다.
        // 여기에 .addValidator() 를 사용하면 특정 데이터가 들어왔을 때, 필터를 걸어 검증하는 역할이다.
        // 특정 데이터를 판독하는 기준은 이전에 우리가 .supports() 메소드에 코딩했던 것과 같다.
        // PasswordForm.class.isAssignableFrom(class) 로 해당 클래스/인터페이스를 구현/상속했는지 확인하고 검증에 들어간다.
        public void initBinder(WebDataBinder webDataBinder) {
            webDataBinder.addValidators(passwordFormValidator);
        }
    
    WebDataBinderクライアントからWebRequestParametersデータを受信しjavaオブジェクト(Java Beans Object)にマッピングした後、.addValidators()に登録されたValidatorで検証する.
    以前にPasswordFormValidatorで作成された.support()は、WebDataBinderからマッピングされたクラスがPasswordForm(PasswordFormクラス、またはPasswordFormクラスを継承)に割り当てられる場合、この検証をサポートすることを示している.
    以下の.validate()の内容は実際の検証内容であり、移管されたオブジェクトをPasswordForm形式に選択する.受信したオブジェクトは、PasswordFormメソッドで.support()で検証されたため、PasswordForm.class.isAssignableFrom()タイプにのみ変換できます.
    いずれにしても、PasswordFormの形式でキャラクタ設定を行い、そのオブジェクトの2つのパスワードが一致していることを確認します.

    その他のGETとPOST方法

        @GetMapping(PASSWORD_MAPPING_PATH)
        public String updatePasswordForm(@LoginAccount Account loginAccount,
                                         Model model) {
            model.addAttribute(loginAccount);
            model.addAttribute(new PasswordForm());
    
            return PASSWORD_MAPPING_PATH;
        }
    
        @PostMapping(PASSWORD_MAPPING_PATH)
        public String updatePassword(
                // Model 맨 뒤로 빼야한다.
                // 왜냐하면 Attribute 들이 매핑돼서 결국 Model에 들어가야 하기 때문
                @LoginAccount Account loginAccount,
                @Valid @ModelAttribute PasswordForm passwordForm,
                Errors errors,
                RedirectAttributes redirectAttributes,
                Model model
        ) {
            if(errors.hasErrors()) {
               model.addAttribute(loginAccount);
               return PASSWORD_MAPPING_PATH;
            }
    
            accountService.updatePassword(loginAccount, passwordForm.getNewPassword());
            redirectAttributes.addFlashAttribute("message", "패스워드를 변경했습니다.");
    
            return "redirect:/" + PASSWORD_MAPPING_PATH;
    上の内容は前に習った内容と同じです.しかし、パラメータではModelが常に最下位にランクされている理由はやはり知られている.ModelAttributeなどのアプリケーションのコンテンツをModelに自動的にマッピングする必要があるため、Modelが最も後ろにない場合、400のエラーが返されます.気をつけて.
    また,パスワード変更部はデータが変化した部分であるため,accountServiceに役割を委任した.

    AccountService


    updatePassword

        public void updatePassword(Account account, String newPassword) {
            account.setPassword(passwordEncoder.encode(newPassword));
        }
    パスワードを入れるときはいつもコードして入れます.

    password.htmlの作成

    <!DOCTYPE html>
    <html lang="en"
          xmlns:th="http://www.thymeleaf.org"
          xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    <head>
        <title>패스워드 수정</title>
        <th:block th:replace="fragments :: headLibraryInjection"></th:block>
    </head>
    
    <body class="bg-light">
    
    <th:block th:replace="fragments :: main-nav"></th:block>
    <div class="alert alert-warning" role="alert" th:if="${account != null && !account?.emailVerified}">
        스터디올래 가입을 완료하려면 <a href="#" th:href="@{/check-email}" class="alert-link">계정 인증 이메일을 확인</a>하세요
    </div>
    
    <div class="container">
        <!-- row의 기본은 col-12만큼의 크기를 갖는다.-->
        <div class="row mt-5 justify-content-center">
            <div class="col-2">
                <div th:replace="fragments :: settings-menu(currentMenu='profile')"></div>
            </div>
            <div class="col-8">
                <div th:if="${message}" class="alert alert-info alert-dismissible fade show mt-3" role="alert">
                    <span th:text="${message}">메시지</span>
                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                        <span aria-hidden="true">x</span>
                    </button>
                </div>
                <div class="row">
                    <h2 class="col-sm-12">패스워드 변경</h2>
                </div>
                <div class="row mt-3">
                    <form class="needs-validation col-12" action="#" th:action="@{/settings/password}"
                          th:object="${passwordForm}" method="post" novalidate>
                        <div class="form-group">
                            <label for="newPassword">새 패스워드</label>
                            <input id="newPassword" type="password" th:field="*{newPassword}"
                                   class="form-control" aria-describedby="newPasswordHelp" required min="8" max="50">
                            <small id="newPasswordHelp" class="form-text text-muted">
                                새 패스워드를 입력하세요.
                            </small>
                            <small class="invalid-feedback">패스워드를 입력하세요.</small>
                            <small class="form-text text-danger" th:if="${#fields.hasErrors('newPassword')}"
                                   th:errors="*{newPassword}">
                                패스워드 너무 길어요.
                            </small>
                        </div>
    
                        <div class="form-group">
                            <label for="newPasswordConfirm">새 패스워드</label>
                            <input id="newPasswordConfirm" type="password" th:field="*{newPasswordConfirm}"
                                   class="form-control" aria-describedby="newPasswordConfirmHelp" required min="8" max="50">
                            <small id="newPasswordConfirmHelp" class="form-text text-muted">
                                새 패스워드를 입력하세요.
                            </small>
                            <small class="invalid-feedback">패스워드를 입력하세요.</small>
                            <small class="form-text text-danger" th:if="${#fields.hasErrors('newPasswordConfirm')}"
                                   th:errors="*{newPasswordConfirm}">
                                패스워드 너무 길어요.
                            </small>
                        </div>
    
                        <div class="form-group">
                            <button class="btn btn-primary btn-block" type="submit"
                                    aria-describedby="submitHelp">수정하기
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <th:block th:replace="fragments :: footer"></th:block>
    </div>
    
    <script th:replace="fragments :: form-validation"></script>
    </body>
    </html>
    以上のように全空間を使い切った場合,col-sm-12のようなクラス名では,smのように解像度に関する部分を入れる必要がないことを認識する.