프로젝트[종료]

13. 로그인 사용자 Session 처리하기

알렉스 페레이라 2023. 4. 28. 19:58

이전까지 간단한 회원가입기능을 만들었다.(아직 할게 많이 남음)

부가적인 기능은 추후로 미루고, 로그인과 관련된 다음 기능을 새로 추가하려고한다.

  • 로그인기능(패스워드를 검증하고 로그인처리)
  • 세션관리(로그인한 사용자를 세션에 담아 관리

 

일단 처음부터 시작을 해보자면,, login관련 HTML과 Controller, Service를 만들어야한다!

 

1.로그인 화면 HTML을 만든다.

html소스는 다음과 같다. 

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{/fragment/meta-fragment :: meta}"></head>
<body class="is-preload">
<div id="wrapper">
    <header id="header" th:replace="~{/fragment/logoMenu-fragment :: logoMenu}"></header>
    <nav id="menu" th:replace="~{/fragment/menu-fragment :: menu}"></nav>
    <div id="main">
        <div class="inner">
            <h1 th:text="#{signIn}">로그인</h1>
            <form method="post" th:action="@{/sign/signIn}" th:object="${signInForm}"> <!-- th:action을 입력하지않으면 현재 url(/add)로 method(POST)를 요청한다.-->
                <div th:if="${#fields.hasGlobalErrors()}">
                    <p class="error" th:each="err : ${#fields.globalErrors()}" th:text="${err}">글로벌 오류 메시지</p>
                </div>

                <div class="row gtr-uniform">                        <!-- th:object는 빈 객체값이다. 각각의 field의 name, id 등을 넣어주기 위해, 그리고 Validation에서 튕겨나갔을시 기본 입력정보는 유지하기 위하여 사용.-->
                    <!--로그인 아이디-->
                    <div class="col-3">
                        <label class="signup-label" for="loginId" th:text="#{signUp.form.loginId}"></label>
                    </div>
                    <div class="col-9"> <!-- th:errorclass를 입력하면 해당 필드에서 error가 발생했을시 입력한 class를 추가해준다. 나같은 경우에는 border를 주기위해 새로 추가하였다.-->
                        <input class="signup-text" th:errorclass="error" type="text" th:field="*{loginId}" name="loginId" id="loginId" value="" th:placeholder="#{signUp.form.loginId.placeholder}" placeholder="로그인 아이디를 입력하세요" />
                        <div class="signup-text-error" th:errors="*{loginId}"></div> <!-- th:errors를 사용하면 해당 필드에 에러가 있을시 bindingResult가 message를 해당 태그에 입력해준다!-->
                    </div>

                    <!--비밀번호-->
                    <div class="col-3">
                        <label class="signup-label" for="password" th:text="#{signUp.form.password}"></label>
                    </div>
                    <div class="col-9">
                        <input class="signup-text" th:errorclass="error" type="password" th:fiend="*{password}" name="password" id="password" th:field=*{password} value="" th:placeholder="#{signUp.form.password.placeholder}" placeholder="비밀번호를 입력하세요" />
                        <div class="signup-text-error" th:errors="*{password}"></div>
                    </div>
                </div>

                <div style="width:50%;margin:0 auto;padding-top:50px;">
                    <ul class="actions fit">
                        <li><button type="submit" class="button fit" th:text="#{signIn}">로그인</button></li>
                        <li><button type="button" th:onclick="|location.href='@{/sign/signUp}'|" class="button fit" th:text="#{signUp}">회원가입</button></li>
                    </ul>
                </div>
            </form>
        </div>

    </div>
    <footer id="footer" th:replace="~{/fragment/contactMe-fragment :: contactMe}"></footer>
</div>
<div th:replace="~{fragment/script-fragment :: script}"></div>
</body>
</html>

 

2.이 외에 추가로 회원가입을 위한 Form을 따로 만들었듯이, 로그인을 위한 Form을 따로 만들었다.

package com.project.domain.sign;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SignInForm {
    @NotBlank(message = "아이디를 입력해주세요.")
    private String loginId;

    @NotBlank(message = "비밀번호를 입력해주세요.")
    private String password;
}

 

3.Controller에 다음과 같이 추가한다.

 

HttpSession이란 서블릿이 제공하는 기능으로, HttpServletRequest안에 존재하여 세션관련 기능을 제공한다.

이에 Session관련 기능을 사용하기 위해 HttpServletRequest를 파라미터로 추가한다.

    //로그인 start
    @GetMapping("/signIn")
    public String getSignIn(@ModelAttribute SignInForm signInForm){
        return "/login/signIn";
    }

    @PostMapping("/signIn")
    public String addSignIn(@Validated @ModelAttribute SignInForm signInForm, BindingResult bindingResult, HttpServletRequest request) {
        if (bindingResult.hasErrors()) {
            return "/login/signIn";
        }

        User user = signService.findLoginUser(signInForm.getLoginId(), signInForm.getPassword());
        if (user == null) {
            bindingResult.addError(new ObjectError("signInForm", "아이디나 비밀번호가 틀렸습니다."));
            return "/login/signIn";
        }else{
            //로그인 성공시 세션처리
            HttpSession httpSession = request.getSession();
            httpSession.setAttribute(SessionConst.SESSION_NAME, user);
        }
        return "redirect:/";
    }
    //로그인 end

 

 

※.GlobalError를 추가하기 위해서는 ObjectError객체를 생성하고, 객체이름을 넣고, 메세지를 추가한다.

    ->ThymeLeaf가 제공하는 GlobalError를 가져오는 메소드를 사용하여 화면에 뿌려준다. 로그인화면에서는 로그인 실패          가 있겠다.

로그인실패시 화면에 뿌려주기 위한 Global Error

 

4.SessionConst.java를 생성한다.

 

package com.project.domain.session;

public interface SessionConst {
    final String SESSION_NAME = "loginUser";
}

->SessionAttribute 이름을 지정해주기 위함이다.

 

로그인 아이디를 잘못 입력했을시 화면

 

로그인에 성공했다면 아래와같이 JSESSIONID에 유니크한 값을 넣어준다.

 

너무 쉬운 내용이라,, 중간중간 생략이 많다. 이 외에도 패스워드가 일치하지 않을시에 Validation을 추가해줬고,

회원가입이 완료되면 Session에 값을 저장해주는 로직을 추가했다.

 

다음에는 SessionFilter관련 글을 작성할 계획이다.