[스프링 부트 쇼핑몰 프로젝트 with JPA] 3. 로그인/로그아웃

2023. 10. 15. 10:22·Web & Android/스프링 부트 쇼핑몰 프로젝트 with JPA
목차
  1. 1. UserDetailService
  2. 2. UserDetails
  3. 3. MemberService 로그인/로그아웃 구현
  4. 4. SecurityConfig 인증 filter 추가
  5. 5. 로그인 페이지
  6. 6. thymeleaf-extras-springsecurity6 의존성 추가
  7. 7. header Navbar 부분 수정
  8. 8. 인증 및 권한에 따른 화면
이 내용은 스프링 부트 쇼핑몰 프로젝트 with JPA 책을 학습한 내용입니다.

1. UserDetailService

  • 데이터베이스에서 회원정보를 가져오는 인터페이스
  • loadUserByUsername() 메소드를 통해 회원 정보를 조회 → 사용자의 정보와 권한을 갖는 UserDetails 인터페이스를 반환

2. UserDetails

  • 회원 정보를 담는 인터페이스
  • 직접 구현하거나 스프링 시큐리티에서 제공하는 User 클래스 사용(구현체)

3. MemberService 로그인/로그아웃 구현

  • MemberService.java
    • UserDetailsService 인터페이스를 구현하고 loadUserByUsername() 메소드 오버라이딩
    • Builder 패턴을 이용하여 UserDetail 인터페이스를 구현한 User 객체 생성 후 반환
package kr.spring.member.service;
import kr.spring.member.entity.Member;
import kr.spring.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
// DB로 값을 가져오거나 controller로 가기 전에 따로 처리해야 할 기능이 있다
@Service
@Transactional
@Log4j2
//final이 붙은 애들을 올려준다 이게 싫으면 @autowired 쓰면 됨
//일반적으로 controller나 service에서 쓰면 상관이 없는데 test에서는 이걸 쓰면 에러가 난다.
@RequiredArgsConstructor
public class MemberService implements UserDetailsService {
private final MemberRepository memberRepository;
public Member saveMember(Member member) {
// 중복확인
validateDuplicate(member);
// 중복확인 후 회원 저장
return memberRepository.save(member);
}
private void validateDuplicate(Member member) {
//이메일로 찾았을 때 값이 있는지 없는지 판단
Member findMember = memberRepository.findByEmail(member.getEmail());
// DB에서 이메일이 검색이 되면 이미 등록되어있는 회원이라는 알림 표시
if(findMember != null) {
throw new IllegalStateException("이미 등록된 사용자 입니다.");
}
}
//implements해놨으니까 추상메소드 구현
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
//DB에 있는 email을 찾아서 잡아온다
Member member = memberRepository.findByEmail(email);
// Optional을 쓰는 경우
// findMember가 null이냐를 물어보는 게 아니라, findMember가 존재하는지 안 존재하는지 물어보는 것
// Optional<Member> findMember = memberRepository.findByEmail(email); -> repository에 Optional로 선언 되어있어야 함.
// 검사식
// if(findMember.isPresent()){
// throw new UsernameNotFoundException(email);
// }
// -> if문 줄여서 쓰기
// Member member = memberRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("해당 사용자 없음 " + email);
//멤버가 없는 경우 (기존에 사용자가 없는 경우)
if(member == null) {
//이메일 정보를 추가해서 exception을 날린다. 이거 근데 로그인이 잘못됐다는 예외가 발생한다
throw new UsernameNotFoundException("해당 사용자가 없습니다." + email);
}
log.info("=================> loadUserByUsername : " + member);
return User.builder()
.username(member.getEmail())//이메일, 아이디 등 어떤 로직으로 로그인을 하던 그 로그인을 할 필드를 넣어준다.
.password(member.getPassword()) //암호화 되어서 들어가야 함.
.roles(member.getRole().toString())//역할을 string으로 넣어줘야 한다. -> enum 안 됨
.build();
}
}

4. SecurityConfig 인증 filter 추가

  • SecurityConfig.java
    • configure(HttpSecurity) 메소드를 통해 로그인 및 로그아웃 URL 지정
    • http.formLogin() - http를 통해 들어오는 form 기반 request를 이용하여 Login을 처리
    • form 태그에서 사용자의 ID 부분은 default 값으로 “username” 필드
  •  
package kr.spring.config;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
// 설정 파일로 쓸 수 있다고 알려주는 어노테이션
@Configuration
// 로그인을 하기 위한 설정
@EnableWebSecurity
public class SecurityConfig {
// 메모리를 미리 올려놔야 하기 때문에 bean 붙이기
@Bean
// http 요청에 대한 보안 설정. 페이지 권한, 로그인 페이지, 로그아웃 메소드 설정 예정
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.formLogin() // 로그인과 관련된 주소
.loginPage("/member/login") // 로그인 주소
.defaultSuccessUrl("/") // 성공 시 이동할 주소
.usernameParameter("email") // user이름을 email로 사용할 것이기 때문에 field이름을 적어줘야 함 -> username이라 적은 경우엔 안적어도 됨
.failureUrl("/member/login/error") // 로그인 실패 시 이동할 페이지
.and()
.logout() // 로그아웃과 관련된 정보
.logoutRequestMatcher(new AntPathRequestMatcher("/member/logout")) // 로그아웃을 누를 때 처리할 내용
.logoutSuccessUrl("/");
http.authorizeHttpRequests() // 인증 여부 확인 -> 스프링 3.0 이하 버전은 authorizeRequests()로 설정
// 스프링 3.0 이하 버전은 antMatchers(), mvcMatchers(), regexMatchers()으로 사용
.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll() // 페이지 이동할 경우 default로 인증이 걸리도록 되어있기 때문에 추가
.requestMatchers("/css/**", "/js/**").permitAll() // 모든 사람에게 css 적용
.requestMatchers("/", "/member/**", "/item/**", "/images/**").permitAll() // 아무나 페이지에 들어올 수 있고, member, item 밑에 있는 애들은 모두 permit 허용
.requestMatchers("/admin/**").hasRole("ADMIN") // admin인 애들만 admin에 접속 가능
.anyRequest().authenticated(); // 인증 받기
http.exceptionHandling() // 권한이 없는 경우
.authenticationEntryPoint(new CustomEntryPoint());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();// 단방향 암호화 객체 생성
}
}
  • AuthenticationManagerBuilder를 통해 AuthenticationManager를 생성하여 인증 처리 수행
  • UserDetailsService 인터페이스를 구현하고 loadUserByUsername 메소드를 오버라이딩한 memberService 객체를 이용하여 User 객체를 얻어낸 뒤, 지정된 비밀번호 암호화 방식으로 비밀번호가 일치하는지 검증
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();// 단방향 암호화 객체 생성
}

5. 로그인 페이지

<!-- 앞으로 우리가 사용할 기본 템플릿 -->
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/layout1}">
<!DOCTYPE html>
<html lang="en" 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">
<!-- post로 날아가기 때문에 이 정보들을 들고 controller로 날아갈 수 있는 것 -->
<form role="form" method="post" action="/member/login">
<div class="form-group">
<!-- 우리가 username이 아닌 email로 로그인을 하기 때문에 이건 userparameter로 security에 적어줘야 한다 -->
<label th:for="email">이메일주소</label>
<input type="email" name="email" class="form-control" placeholder="이메일을 입력해주세요">
</div>
<div class="form-group">
<!-- default는 password. 이거 바꾸면 이것도 security에 적어줘야 한다 -->
<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='/member/new'">회원가입</button>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
</form>
</div>
</html>

6. thymeleaf-extras-springsecurity6 의존성 추가

  • 로그인한 상태에서는 로그아웃만 노출, 상품 등록 메뉴는 관리자로 로그인 했을 때만 노출되도록 인증 및 권한에 따라 설정 변경을 도와주는 라이브러리
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE'

7. header Navbar 부분 수정

<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<!-- 부트스트랩 이용함 -->
<div th:fragment="header">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="/">Woojin's Shop</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<!-- 상품등록 -->
<li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
<a class="nav-link active" aria-current="page" href="/admin/item/new" >상품등록</a></li>
<!-- 상품관리 -->
<li class="nav-item" sec:authorize="hasAnyAuthority('ROLE_ADMIN')">
<a class="nav-link active" aria-current="page" href="/admin/items">상품관리</a></li>
<!-- 장바구니 -->
<li class="nav-item" sec:authorize="isAuthenticated()">
<a class="nav-link active" aria-current="page" href="/cart">장바구니</a></li>
<!-- 구매이력 -->
<li class="nav-item" sec:authorize="isAuthenticated()">
<a class="nav-link active" aria-current="page" href="/orders">구매이력</a></li>
<!-- 게시판 -->
<li class="nav-item" sec:authorize="isAuthenticated()">
<a class="nav-link active" aria-current="page" href="/board">게시판</a></li>
<!-- 로그인 -->
<li class="nav-item" sec:authorize="isAnonymous()">
<a class="nav-link active" aria-current="page" href="/member/login">로그인</a></li>
<!-- 로그아웃 -->
<li class="nav-item" sec:authorize="isAuthenticated()">
<a class="nav-link active" aria-current="page" href="/member/logout">로그아웃</a></li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search"
aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
</div>
</html>

8. 인증 및 권한에 따른 화면

  • Guest 상태

  • 로그인 상태

  • ADMIN 권한 화면

저작자표시 비영리 변경금지 (새창열림)

'Web & Android > 스프링 부트 쇼핑몰 프로젝트 with JPA' 카테고리의 다른 글

[스프링 부트 쇼핑몰 프로젝트 with JPA] 5. Entity 공통 속성 공통화(Auditing)  (0) 2023.10.15
[스프링 부트 쇼핑몰 프로젝트 with JPA] 4. 페이지 권한 설정  (0) 2023.10.15
[스프링 부트 쇼핑몰 프로젝트 with JPA] 2-3. 회원가입 검증  (0) 2023.10.15
[스프링 부트 쇼핑몰 프로젝트 with JPA] 2-2. 회원가입 페이지  (0) 2023.10.15
[스프링 부트 쇼핑몰 프로젝트 with JPA] 2-1. 회원가입 로직  (0) 2023.10.15
  1. 1. UserDetailService
  2. 2. UserDetails
  3. 3. MemberService 로그인/로그아웃 구현
  4. 4. SecurityConfig 인증 filter 추가
  5. 5. 로그인 페이지
  6. 6. thymeleaf-extras-springsecurity6 의존성 추가
  7. 7. header Navbar 부분 수정
  8. 8. 인증 및 권한에 따른 화면
'Web & Android/스프링 부트 쇼핑몰 프로젝트 with JPA' 카테고리의 다른 글
  • [스프링 부트 쇼핑몰 프로젝트 with JPA] 5. Entity 공통 속성 공통화(Auditing)
  • [스프링 부트 쇼핑몰 프로젝트 with JPA] 4. 페이지 권한 설정
  • [스프링 부트 쇼핑몰 프로젝트 with JPA] 2-3. 회원가입 검증
  • [스프링 부트 쇼핑몰 프로젝트 with JPA] 2-2. 회원가입 페이지
woojin._.
woojin._.
여러가지 개발을 해보며 발생하는 이야기들에 대한 블로그입니다:)
  • woojin._.
    Jin's Dev Story
    woojin._.
  • 전체
    오늘
    어제
    • 분류 전체보기 (827) N
      • Tools (25)
        • eGovFrame (3)
        • GeoServer (3)
        • QGIS (2)
        • LabelImg (2)
        • Git (6)
        • GitHub (1)
        • Eclipse (7)
        • Visual Studio (1)
      • Web & Android (121)
        • SpringBoot (37)
        • Three.js (2)
        • Spring Data JPA (9)
        • 스프링 부트 쇼핑몰 프로젝트 with JPA (25)
        • Thymeleaf (4)
        • Spring Security (15)
        • Flutter (29)
      • Programming Language (61)
        • JAVA (27)
        • JavaScript (14)
        • Dart (2)
        • Python (15)
        • PHP (3)
      • Database (43)
        • PostgreSQL (32)
        • MYSQL (7)
        • Oracle (3)
        • MSSQL (1)
      • SERVER (17)
        • TCP_IP (3)
        • 리눅스 (7)
        • AWS (7)
      • Coding Test (443) N
        • 백준[JAVA] (106) N
        • 프로그래머스[JAVA] (260)
        • 알고리즘 고득점 Kit[JAVA] (3)
        • SQL 고득점 Kit[ORACLE] (74)
      • CS 지식 (49)
        • [자료구조] (14)
        • [네트워크] (12)
        • [데이터베이스] (10)
        • [알고리즘] (9)
        • [운영체제] (4)
      • 기타 (6)
      • 자격증 & 공부 (62)
        • 정보처리기사 (2)
        • SQLD (6)
        • 네트워크관리사 2급 (5)
        • 리눅스마스터 1급 (44)
        • 리눅스마스터 2급 (1)
        • ISTQB (3)
        • 시스템보안 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    programmers
    CS지식
    데이터
    springboot
    리눅스
    pcce 기출문제
    JPA
    postgresql
    baekjoon
    리눅스마스터 1급
    시큐리티
    플러터
    Flutter
    CS
    spring
    리눅스마스터
    Spring Security
    프로그래머스
    백준
    스프링
    자바
    데이터베이스
    Java
    스프링부트
    스프링 부트 쇼핑몰 프로젝트 with JPA
    Oracle
    backjoon
    DB
    Linux
    python
  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
woojin._.
[스프링 부트 쇼핑몰 프로젝트 with JPA] 3. 로그인/로그아웃

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.