LUMI_dev
사용자 관리하기 - #1. 회원가입 구현 (구현 편) / 양방향, 단방향 암호 알고리즘 본문
스파르타 코딩 클럽 | 자바 심화 과정/Spring Master (숙련 주차)
사용자 관리하기 - #1. 회원가입 구현 (구현 편) / 양방향, 단방향 암호 알고리즘
luminous_dev 2025. 2. 5. 01:52User 테이블
컬럼명 | 컬럼타입 | 중복허용 | 설명 |
id | Long | X | 테이블 ID (PK) |
username | String | X | 회원 ID |
password | String | O | 패스워드 |
String | X | 이메일 주소 | |
role | String | O | 역할 1) 사용자: USER 2) 관리자: ADMIN |
User.java
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) //만약 여기에 UserRoleEnum의 USER(Authority.USER)를 넣으면 그 값이 생긴 그대로 들어감 - USER로 저장될 것임
private UserRoleEnum role;
}
@Enumerated(value = EnumType.STRING)
- 데이터 enum타입을 데이터 베이스 컬럼에 저장할 때 사용
- EnumType.STRING이라는 옵션 사용 : enum의 이름 그대로를 데이터베이스에 저장
- ex) USER(Authority.USER) → USER
관리자 회원 가입 인가 방법 (토큰 x)
- 관리자 권한을 부여할 수 있는 관리자 페이지 구현
- 승인자에 의한 결재 과정 구현 → 관리자 권한 부여
패스워드 암호화
비밀번호는 암호화 (Encryption)가 의무
- 암호화 후 패스워드 저장이 필요 합니다.
- 평문 → (암호화 알고리즘) → 암호문
복호화가 불가능한 '단방향'암호 알고리즘 사용이 필요
- 평문 → (암호화 알고리즘) → 암호문
양방향 ↔ 단방향 암호화 알고리즘
양방향 암호 알고리즘
- 암호화: 평문 → (암호화 알고리즘) → 암호문
- 복호화: 암호문 → (암호화 알고리즘) → 평문
단방향
- 암호화: 평문 → (암호화 알고리즘) → 암호문
- 복호화: 불가 (
암호문 → (암호화 알고리즘) → 평문)
Q. 그럼 사용자가 로그인할 때는 암호화된 패스워드를 기억해야하나?
Password 확인절차 사용자가 로그인을 위해 "아이디, 패스워드 (평문)" 입력
→ 서버에 로그인 요청 서버에서 패스워드 (평문) 을 암호화 평문 → (암호화 알고리즘)
→ 암호문 DB 에 저장된 "아이디, 패스워드 (암호문)"와 일치 여부 확인
User.java (Entity)
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) //만약 여기에 UserRoleEnum의 USER(Authority.USER)를 넣으면 그 값이 생긴 그대로 들어감 - USER로 저장될 것임
private UserRoleEnum role;
public User(String username, String password, String email, UserRoleEnum role) {
this.username = username;
this.password = password;
this.email = email;
this.role = role;
}
}
UserRoleEnum.java(Entity)
package com.sparta.springauth.entity;
public enum UserRoleEnum {
USER(Authority.USER), // 사용자 권한 //Authority.USER 여기에 값을 넣어줄 수 있음 - 여기 넣는 값은 생성자가 됨
ADMIN(Authority.ADMIN); // 관리자 권한
private final String authority;
UserRoleEnum(String authority) {
this.authority = authority;
}
public String getAuthority() { //getAuthority하면 ROLE_USER,ROLE_ADMIN가져올 수 있음
return this.authority;
}
public static class Authority {
public static final String USER = "ROLE_USER";//USER은 ROLE_USER라는 이름을 갖게 됨
public static final String ADMIN = "ROLE_ADMIN"; //ADMIN은 ROLE_ADMIN이라는 이름을 갖게 됨
}
}
HomeController.java
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";
}
}
AuthController 단
package com.sparta.springauth.auth;
import com.sparta.springauth.entity.UserRoleEnum;
import com.sparta.springauth.jwt.JwtUtil;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class AuthController {
public static String AUTHORIZATION_HEADER = "Authorization";
private final JwtUtil jwtUtil;
public AuthController(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
// jwt를 받아오지 못해서 jwtUtil에 빨간 줄
//JwtUtil.java 보면 jwt를 컴포넌트(@Component) 로 지정해놓음 - Bean이니까 가져오기
//JWT를 만드는 코드
@GetMapping("/create-jwt")
public String createJwt(HttpServletResponse res) {
// Jwt 생성
String token = jwtUtil.createToken("Robbie", UserRoleEnum.USER);//UserRoleEnum.USER 권한 = 일반 유저
// Jwt 쿠키 저장
jwtUtil.addJwtToCookie(token, res); //JWT에서 만든 것 사용
return "createJwt : " + token;
}
@GetMapping("/get-jwt")
public String getJwt(@CookieValue(JwtUtil.AUTHORIZATION_HEADER) String tokenValue) {
//토큰의 name부분이 Authorization
// JWT 토큰 substring
String token = jwtUtil.substringToken(tokenValue);
// 토큰 검증
if(!jwtUtil.validateToken(token)){
throw new IllegalArgumentException("Token Error");
}
// 토큰에서 사용자 정보 가져오는 법
Claims info = jwtUtil.getUserInfoFromToken(token);
// 사용자 username 가져오는 법
String username = info.getSubject();
System.out.println("username = " + username);
// 사용자 권한 가져오는 법
String authority = (String) info.get(JwtUtil.AUTHORIZATION_KEY); //JwtUtil의 .claim(AUTHORIZATION_KEY, role) // 사용자 권한 .claim(key,value) 참고
System.out.println("authority = " + authority);
return "getJwt : " + username + ", " + authority;
}
}
UserController 단
package com.sparta.springauth.controller;
import com.sparta.springauth.dto.SignupRequestDto;
import com.sparta.springauth.service.UserService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/api")
public class UserController {
//주입
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
//로그인 페이지
@GetMapping("/user/login-page")
public String loginPage() {
return "login";
}
//회원 가입 페이지
@GetMapping("/user/signup")
public String signupPage() {
return "signup";
}
@PostMapping ("/user/signup")
public String signup(SignupRequestDto requestDto) { //객체로 받고 있음
userService.signup(requestDto);
return "redirect:/api/user/login-page";
}
}
서비스 단
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; //interface
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()) { //.isPresent() : 값이 존재하는지 아닌지
throw new IllegalArgumentException("중복된 Email 입니다.");
}
// 사용자 ROLE 확인
UserRoleEnum role = UserRoleEnum.USER;//사용자 권한을 일단 설정해둠
if (requestDto.isAdmin()) { //.isAdmin하면 Dto의 boolean admin값 가져옴
if (!ADMIN_TOKEN.equals(requestDto.getAdminToken())) {
throw new IllegalArgumentException("관리자 암호가 틀려 등록이 불가능합니다.");
}
role = UserRoleEnum.ADMIN; //어드민 권한으로 덮어씀
}
// 사용자 등록
//테이블의 한 행에 해당하는 데이터를 만들어야 함
User user = new User(username, password, email, role);
userRepository.save(user); //repository에 의해 저장
}
}
회원 중복 체크
User.java에서 유니크 키로 설정
.isAdmin() 하면 DTO의 boolean 값을 가져옴
규칙) boolean은 is로 시작함
Repository 단
package com.sparta.springauth.repository;
import com.sparta.springauth.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
//users 테이블의 Entity 객체를 넣어야 함
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
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 = "";
}
관리자 로그인
'스파르타 코딩 클럽 | 자바 심화 과정 > Spring Master (숙련 주차)' 카테고리의 다른 글
JWT 다루기 (1) | 2025.02.06 |
---|---|
사용자 관리하기 - #2. 로그인 구현 JWT (1) | 2025.02.05 |
사용자 관리하기 - #1. 회원가입 구현 (설정 편) (0) | 2025.02.05 |
인증과 인가란? (1) | 2025.02.04 |
Bean - #2.같은 타입의 Bean이 2개라면?_@Primary, @Qualifier (1) | 2025.02.04 |