Spring 숙련 1주차 (4)

신성훈·2024년 6월 5일

TIL

목록 보기
32/162
post-thumbnail

오늘의 학습 키워드

  • 회원가입 구현

회원가입 구현

  • 프로젝트 설정추가
    -build.gradle
    -> build.gradle : JPA, MySQL 추가
// JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
  • application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/{생성한 테이블명}
spring.datasource.username=root
spring.datasource.password={비밀번호}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.hibernate.ddl-auto=update

spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
  • 페이지 Controller
package com.sparta.springauth.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

	@GetMapping("/")
	public String home(Model model) {
		model.addAttribute("username", "username");
		return "index";
	}
}
  • UserController
package com.sparta.springauth.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/api")
public class UserController {

	@GetMapping("/user/login-page")
	public String loginPage() {
		return "login";
	}
    
	@GetMapping("/user/signup")
	public String signupPage() {
		return "signup";
	}
}
  • 회원가입 설계
    -User
package com.sparta.springauth.entity;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "users")
public class User {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@Column(nullable = false, unique = true)
	private String username;

	@Column(nullable = false)
	private String password;

	@Column(nullable = false, unique = true)
	private String email;

	@Column(nullable = false)
	@Enumerated(value = EnumType.STRING)
	private UserRoleEnum role;
}
  • @Enumerated(value = EnumType. STRING )
    -EnumType을 DB 컬럼에 저장할 때 사용하는 애너테이션
    -EnumType. STRING 옵션을 사용하면 Enum의 이름을 DB에 그대로 저장
    -USER(Authority.USER) → USER


  • 관리자 회원 가입 인가 방법
    -'관리자 가입 토큰' 입력 필요 : 랜덤하게 생성된 토큰 사용
"AAABnvxRVklrnYxKZ0aHgTBcXukeZygoC"

보통 현업에서는
-1) '관리자' 권한을 부여할 수 있는 관리자 페이지 구현
-2) 승인자에 의한 결재 과정 구현 → 관리자 권한 부여

  • 패스워드 암호화 이해
    -회원 등록 시 '비밀번호'는 사용자가 입력한 문자 그대로 DB 에 등록하면 안 된다.
    '정보통신망법, 개인정보보호법' 에 의해 비밀번호 암호화(Encryption)가 의무

    -암호화 후 패스워드 저장이 필요

    • 평문 → (암호화 알고리즘) → 암호문
      ->"nobodynobody" → "2a$10.."
      -패스워드 정보를 갈취하더라도 실제 암호를 알 수 없습니다. 그래서 복호화가 불가능한 '단
      방향' 암호 알고리즘 사용이 필요
  • 양반향 대 단방향
    -양방향 암호 알고리즘

    • 암호화: 평문 → (암호화 알고리즘) → 암호문
    • 복호화: 암호문 → (암호화 알고리즘) → 평문

    -단방향 암호 알고리즘

    • 암호화: 평문 → (암호화 알고리즘) → 암호문
    • 복호화: 불가 (암호문 → (암호화 알고리즘) → 평문)
  • Password 확인절차

    1. 사용자가 로그인을 위해 "아이디, 패스워드 (평문)" 입력 → 서버에 로그인 요청
      a. 서버에서 패스워드 (평문) 을 암호화
      b. 평문 → (암호화 알고리즘) → 암호문

    2. DB 에 저장된 "아이디, 패스워드 (암호문)"와 일치 여부 확인
  • Password Matching
    -Spring Security 이용하여 PasswordEncoder가 해당 Security에서 제공하는 비밀번호 암호화 메서드이다.
    -사용자가 입력한 비밀번호를 암호화되어 저장된 비밀번호와 비교하여 일치여부를 확인해주는 기능도 가지고 있어 많이 사용
// 사용예시
// 비밀번호 확인
if(!passwordEncoder.matches("사용자가 입력한 비밀번호", "저장된 비밀번호")) {
		throw new IllegalAccessError("비밀번호가 일치하지 않습니다.");
}
  • boolean matches(CharSequence rawPassword, String encodedPassword);
    -rawPassword : 사용자가 입력한 비밀번호
    -encodedPassword : 암호화되어 DB 에 저장된 비밀번호

  • SignupRequestDto
package com.sparta.springauth.dto;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class SignupRequestDto {
	private String username;
	private String password;
	private String email;
	private boolean admin = false;
	private String adminToken = "";
}
  • UserService
package com.sparta.springauth.service;

import com.sparta.springauth.dto.SignupRequestDto;
import com.sparta.springauth.entity.User;
import com.sparta.springauth.entity.UserRoleEnum;
import com.sparta.springauth.repository.UserRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class UserService {
	
    private final UserRepository userRepository;
	private final PasswordEncoder passwordEncoder;

	public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
		this.userRepository = userRepository;
		this.passwordEncoder = passwordEncoder;
	}
    
	// ADMIN_TOKEN
	private final String ADMIN_TOKEN = "AAABnvxRVklrnYxKZ0aHgTBcXukeZygoC";

	public void signup(SignupRequestDto requestDto) {
		String username = requestDto.getUsername();
		String password = passwordEncoder.encode(requestDto.getPassword());

		// 회원 중복 확인
		Optional<User> checkUsername = userRepository.findByUsername(username);
		if (checkUsername.isPresent()) {
		throw new IllegalArgumentException("중복된 사용자가 존재합니다.");
		}
        
		// email 중복확인
		String email = requestDto.getEmail();
		Optional<User> checkEmail = userRepository.findByEmail(email);
		if (checkEmail.isPresent()) {
			throw new IllegalArgumentException("중복된 Email 입니다.");
		}
        
		// 사용자 ROLE 확인
		UserRoleEnum role = UserRoleEnum.USER;
		if (requestDto.isAdmin()) {
		if (!ADMIN_TOKEN.equals(requestDto.getAdminToken())) {
			throw new IllegalArgumentException("관리자 암호가 틀려 등록이 불가능합니다.");
			}
			role = UserRoleEnum.ADMIN;
		}
		// 사용자 등록
		User user = new User(username, password, email, role);
		userRepository.save(user);
	}
}
profile
조급해하지 말고, 흐름을 만들고, 기록하면서 쌓아가자.

0개의 댓글