1. UserDetailsService
2. UserDetails 
3. MemberService 로그인 / 로그아웃 구현 

4. SecurityConfig 인증 filter 추가 


5. 로그인 페이지 
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layouts/layout1}">
<!-- 사용자 CSS 추가 -->
<th:block layout:fragment="css">
    <style>
        .error {
            color: #bd2130;
        }
    </style>
</th:block>
<div layout:fragment="content">
    <form role="form" method="post" action="/members/login">
        <div class="form-group">
            <label th:for="email">이메일주소</label>
            <input type="email" name="email" class="form-control" placeholder="이메일을 입력해주세요">
        </div>
        <div class="form-group">
            <label th:for="password">비밀번호</label>
            <input type="password" name="password" id="password" class="form-control" placeholder="비밀번호 입력">
        </div>
        <p th:if="${loginErrorMsg}" class="error" th:text="${loginErrorMsg}"></p>
        <button class="btn btn-primary">로그인</button>
        <button type="button" class="btn btn-primary" onClick="location.href='/members/new'">회원가입</button>
        <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
    </form>
</div>
</html>
6. spring-security-test 의존성 주입 
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
    <version>${spring-security.version}</version>
</dependency>
7. 로그인 테스트


formLogin() - form 태그 기반의 로그인 인증 방식(http.formLogin())을 테스트하기 위해 form 태그 기반 POST request 객체를 생성
loginProcessingUrl() - 요청 URL 설정 (formLogin() 메소드의 매개변수로 설정해도됨)
userParameter("email") - formLogin 방식에서 Request 메시지 Body 부분은 "username"=value 가 default 값이기 때문에 "email"=value 로 변경 
user().password() - Requset 메시지 Body Data 설정

8. thymeleaf-extras-springsecurity5 의존성 추가 
<dependency>
      <groupId>org.thymeleaf.extras</groupId>
      <artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
9. header Navbar 부분 수정  
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<div th:fragment="header">
    <nav class="navbar navbar-expand-sm bg-primary navbar-dark">
        <button class="navbar-toggler" type="button" data-toggle="collapse"
                data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03"
                aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <a class="navbar-brand" href="/">Shop</a>
        <div class="collapse navbar-collapse" id="navbarTogglerDemo03">
            <ul class="navbar-nav mr-auto mt-2 mt-lg-0">
                <li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
                    <a class="nav-link" href="/admin/item/new">상품 등록</a>
                </li>
                <li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
                    <a class="nav-link" href="/admin/items">상품 관리</a>
                </li>
                <li class="nav-item" sec:authorize="isAuthenticated()">
                    <a class="nav-link" href="/cart">장바구니</a>
                </li>
                <li class="nav-item" sec:authorize="isAuthenticated()">
                    <a class="nav-link" href="/orders">구매이력</a>
                </li>
                <li class="nav-item" sec:authorize="isAnonymous()">
                    <a class="nav-link" href="/members/login">로그인</a>
                </li>
                <li class="nav-item" sec:authorize="isAuthenticated()">
                    <a class="nav-link" href="/members/logout">로그아웃</a>
                </li>
            </ul>
            <form class="form-inline my-2 my-lg-0" th:action="@{/}" method="get">
                <input name="searchQuery" class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>
        </div>
    </nav>
</div>
</html>
10. 인증 및 권한에 따른 화면  

로그인  상태

ADMIN 권한 화면은 권한 설정 참고
