jhhan의 블로그

Spring_Security 응용 - 로그인 페이지 만들기(4)_회원가입 본문

Spring

Spring_Security 응용 - 로그인 페이지 만들기(4)_회원가입

jhhan000 2020. 3. 22. 23:58

저번 포스트에 이어서 이번에는 회원가입 페이지를 만들어 보겠습니다.

(다시 보니 코드를 보기 힘드실 수도 있을 것 같습니다.. 

아직도 코드를 올리는 것은 힘드네요.. 

사진으로 올릴지 이런 식으로 올릴지는 좀 더 고민해봐야겠습니다..)

 

 

이런 화면이 나오도록 진행할 것입니다.

<div>
        <a href="/">Main</a>
        <a href="/report">ReportSystem</a>
        <a href="/board">게시판</a>
        <a href="/signUp">SignUp</a>

        <form name="f" th:action="@{/login}" method="post">
            <fieldset>
                <legend>Please LogIn</legend>
                <div th:if="${param.error}" class="alert alert-error">
                    <strong>Username should be end with '@pharmcadd.com'. Check your Username and Password.</strong>
                </div>
                <div th:if="${param.logout}" class="alert alert-error">
                    You have been logged out.
                </div>
                <label for="username">UserName</label>
                <div>
                    <input type="text" id="username" name="username" /><br/>
                </div>
                <label for="password">Password </label>
                <div>
                    <input type="password" id="password" name="password" />
                </div>
                <div class="form-actions">
                    <button type="submit" class="btn">LogIn</button>
                </div>
            </fieldset>
        </form>
    </div>

저번에 만들었던 로그인 화면에 이렇게 변경하시면 위와 같은 화면이 나오게 될 것입니다.

 

그리고 <a href="/signUp">SignUp</a> 에 해당하는 부분을 컨트롤러에 추가해야합니다.

@GetMapping("/signUp")
    public String SignUpForm(Model model) {
        return "signUp/sign_up";
    }

컨트롤러에 이렇게 추가하시면 됩니다.

  • 저는 저번부터 진행했던 TestController에 추가를 했습니다. 본인이 원하시는 컨트롤러를 만드셔서 진행하셔도 상관없습니다.
  • return "signUp/sign_up" 부분은 프로젝트 구조에서 resoucres/templates 에 signUp 폴더를 만든 후 sign_up html파일을 만듭니다. 

이제 signUp html파일을 만들겠습니다.

파일의 위치는 저의 경우 resoucres/templates/signUp/sign_up.html로 설정했습니다. -> 아 위에 적었군요.

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>회원가입</title>
    <link rel="stylesheet" href="/bootstrap.css">
    <link rel="stylesheet" href="/bootstrap-grid.css">
    <link rel="stylesheet" href="/bootstrap-reboot.css">
    <link rel="stylesheet" href="/board.css">
</head>
<body>
    <div class="container">
        <div class="t-c">
            <h2>회원가입</h2>
        </div>
        <a href="/">메인으로</a>
        <div>
            <h5>회원정보</h5>
            <form class="needs-validation" novalidate th:action="@{/signUp}" method="post">
                <div>
                    <label for="username">아이디(username)</label>
                    <div>
                        <input type="text" id="username" class="form-control" placeholder="AAA@pharmcadd.com" required name="user_id" />
                        <div class="invalid-feedback" style="width: 100%;">Your username is required.</div>
                    </div>
                </div>
                <div>
                    <label for="realname">이름(realname)</label>
                    <div>
                        <input type="text" id="realname" class="form-control" placeholder="Your English Name" required name="user_realname" />
                        <div class="invalid-feedback" style="width: 100%;">Your real_name is required.</div>
                    </div>
                </div>
                <div>
                    <label for="password">비밀번호(password)</label>
                    <div>
                        <input type="password" id="password" class="form-control" required name="user_password" />
                    </div>
                </div>
                <div>
                    <label for="password">비밀번호 확인(password_check)</label>
                    <div>
                        <input type="password" id="pw_check" class="form-control" required name="user_password_check" />
                    </div>
                </div>
                <button class="btn btn-primary" type="submit">가입하기</button>
                <button class="btn"><a href="login">취소</a></button>
            </form>
        </div>
    </div>
</body>
</html>

sign_up.html 파일입니다.

class="needs-validation" 부분은 제가 제대로 활용하지 못한 부분입니다. 이 부분은 따로 찾아보셔서 해결하셔야 합니다.

제 코드대로 진행하시면 오류가 나지는 않지만 해당 기능은 사용하지 못합니다.

sign_up 화면

실행하시면 다음과 같은 화면을 얻을 수 있을 것입니다.

 

bootstrap관련 파일을 적은 것이 보일 텐데 이 부분은 bootstrap 홈페이지에 들어가셔서 다운받은 다음

resources/static에 포함시켰습니다.

  • 다음은 파일 구조 중 bootstrap이 포함된 부분입니다.
  • board.css는 제가 만든 파일입니다. 
@charset "UTF-8";

.text-red {
        color:red;
}

.text-blue {
        color:blue;
}

.text-grey {
        color:grey;
}
.t-c {
    text-align: center;
}

.t-r {
    text-align: right;
}

board.css에 들어간 내용입니다. 여기서 더 추가하고 싶은 것은 추가하셔도 됩니다.

 

회원가입의 경우는 Post방식으로 해야 해당정보들이 url에 등장하지 않기 때문에 post를 이용합니다.

이제 controller에 회원가입이 이루어지도록 코드를 쓰겠습니다.

@PostMapping("/signUp")
    public String SignUpFunction(Model model, @RequestParam Map<String, String> params) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        System.out.println(params); // 값들이 잘 넘어오는지 확인

        String userID = params.get("user_id");
        String userPW = params.get("user_password");
        String checkPW = params.get("user_password_check");
        String realName = params.get("user_realname");
        int loc = userID.indexOf("@naver.com");
        System.out.println(loc);

        //back-end validation
        String result = "";
        boolean isValidate = true;
        if(loc < 0) { // @naver.com으로 끝나는지 확인
            result += "user_id should be end with '@naver.com'. ";
            isValidate = false;
        } if(userPW.length() < 4) {
            result += "user_password should be at least 4 length. ";
            isValidate = false;
        } if(realName.length() <= 0) {
            result += "realname should be entered. ";
            isValidate = false;
        } if(!userPW.equals(checkPW)) {
            result += "password and password_check should be same. ";
            isValidate = false;
        }

        //submit to database
        if(isValidate) {
            params.remove("_csrf");
            params.put("user_password", passwordEncoder.encode(userPW));
            try {
                int rs = sud.InsertUserInfo(params);
                if(rs<1) {
                    result += "SignUp_failed. Duplicate Information or Other Problems. ";
                    isValidate=false;
                } else {
                    result += "SignUp is completed! ";
                }
            } catch(Exception e) {
                e.printStackTrace();
                result += "SignUp_failed. Duplicate Information or Other Problems. ";
                isValidate = false;
            }
        }

        if(isValidate) {
            try {
                int rs = sud.InsertAuthorityInfo(userID);
                if(rs<1) {
                    result += "SignUp_failed. Check your Information and try again. ";
                    isValidate=false;
                } else {
                    result += "SignUp is completed! ";
                }
            } catch (Exception e) {
                e.printStackTrace();
                result += "SignUp_failed. Check your Information and try again. ";
                isValidate=false;
            }
        }

        model.addAttribute("isSuccess",isValidate);
        model.addAttribute("resultMSG",result);

        return "signUp/sign_up_result";
    }
  • 이런 코드를 추가합니다.
  • 제가 적은 TestController에 이렇게 적었습니다.
  • sud라는 변수는 JDBCTemplate를 다루기 위한 변수입니다. 밑에서 다시 설명하겠습니다.
  • 이메일의 경우 원래는 회사 이메일로 했지만, 글을 올릴 때는 어쩔 수 없이 naver만 되도록 했습니다.
  • 어쨌든 naver 이메일이 아니면 가입이 되지 않도록 했습니다.
  • result에 메시지를 담게해서 성공여부와 실패이유를 담을 수 있도록 했습니다.
  • 저는 User테이블과 Authority테이블을 따로 나눠서 db에 저장하는 법이 복잡합니다.

  • sud의 경우 TestController에 선언합니다.
  • 이제 SimplerUserDao라는 클래스도 만듭니다.

  • 대략적인 파일 구조입니다.
  • 저런 식으로 SimpleUserDao를 생성하고 다음과 같이 작성합니다.
package com.example.security.Dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Map;

@Repository
public class SimpleUserDao {
    @Autowired
    JdbcTemplate jt;

    public int InsertUserInfo(Map<String, String> user) {
        String sql = "insert into users values(?,?,1,?)";

        return jt.update(sql,
                user.get("user_id"),
                user.get("user_password"),
                user.get("user_realname")
        );
    }

    public int InsertAuthorityInfo(String user_id) {
        String sql = "insert into authorities values(?,'USER')";

        return jt.update(sql, user_id);
    }
}

 

  • JdbcTemplate을 이용해서 db에 저장합니다.
  • User테이블과 Authority테이블을 따로 나눠서 저렇게 두번 저장합니다.. 테이블을 좀 더 효율적으로 구성하시고 진행하는것이 좋다고 생각합니다.. 저처럼 하지 마시고..

 

이제 회원가입의 결과를 보여주는 페이지를 만들겠습니다.

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="UTF-8">
    <title>회원가입 결과</title>
    <link rel="stylesheet" href="/board.css">
</head>
<body>
    <h2 class="t-c">회원가입 결과여부</h2>
    <div class="t-c">
        <p th:text="${resultMSG}"></p>
        <p>
            <a href="/signUp" th:unless="${isSuccess}">회원가입 다시하기</a>
            <a href="/" th:if="${isSuccess}">메인으로</a>
        </p>
    </div>
</body>
</html>
  • 저는 이렇게 구성했습니다. 디자인은 생각하지 않고 만들었기 때문에 디자인적인 부분은 따로 처리하셔야 합니다.
  • 회원가입 성공여부에 따라 링크가 달라지도록 했습니다.
  • 그리고 화면입니다.

회원가입 성공화면

 

회원가입 실패화면

그리고 DB(HeidiSQL 실행 시, MariaDB)를 실행하면 본인이 입력했던 정보가 추가된 것을 확인할 수 있습니다.

또 회원가입한 정보로 로그인이 가능할 것입니다.

 

db와 관련된 경우, JPA를 쓰는 것이 좀 더 나을 것 같지만, 이 포스트를 올릴 때에는 JPA 사용법에 익숙하지 않아서 JdbcTemplate을 사용했습니다.

회원가입 예제를 더 발전하면, 인증메일을 전송해서 인증을 거친 후에 회원가입이 되게 할 수 있지만 그건 복잡해서 올릴지 말지 생각 중입니다..