Loading the catalog…
Loading the catalog…
Spring 핵심 개념 정리 1. Bean 수동 등록 Spring에서 객체를 Bean으로 등록하는 방법에는 크게 컴포넌트 스캔을 이용한 자동 등록 과 @Bean 을 이용한 수동 등록 이 있다. 수동 등록 대표적으로 직접 생성하기 어려운 객체나 라이브러리 객체를 Bean으로 등록할 때 사용한다. @Configuration public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 이렇게 등록하면 Spring Container가 PasswordEncoder 객체를 관리한다. BCryptPasswordEncoder 비밀번호를 저장할 때 평문 그대로 저장하면 보안상 위험하다. 평문 비밀번호 password123 이를 BCrypt로 해싱하면 다음과 같이 알아볼 수 없는 값으로 저장된다. $2a$10$... 정확히 말하면 BCrypt는 일반적인 의미의 "암호화(Encryption)"보다는 단방향 해시(Hashing) 에 가깝다. 따라서 사용자가 로그인할 때는 입력받은 비밀번호를 다시 BCrypt 방식으로 검증하여 DB에 저장된 해시와 일치하는지 확인한다. 2. 같은 타입의 Bean이 여러 개 존재하는 경우 Spring에서 같은 타입의 Bean이 여러 개 등록되어 있으면 어떤 Bean을 주입해야 하는지 결정할 수 없는 문제가 발생할 수 있다. 예를 들어: @Bean public PasswordEncoder encoder1() { return new BCryptPasswordEncoder(); } @Bean public PasswordEncoder encoder2() { return new BCryptPasswordEncoder(); } PasswordEncoder 타입의 Bean이 2개 존재한다. @Autowired private PasswordEncoder passwordEncoder; 이 경우 Spring 입장에서는 PasswordEncoder가 2개인데 어떤 것을 주입해야 하지? 라는 문제가 발생한다. 해결 방법 1. @Qualifier 특정 Bean을 명시적으로 지정한다. @Autowired @Qualifier("encoder1") private PasswordEncoder passwordEncoder; 해결 방법 2. @Primary 기본적으로 사용할 Bean을 지정한다. @Bean @Primary public PasswordEncoder encoder1() { return new BCryptPasswordEncoder(); } 이후 별도의 지정이 없다면 encoder1 이 우선적으로 선택된다. Qualifier와 Primary가 동시에 존재한다면? @Qualifier 가 더 높은 우선순위를 가진다. @Autowired @Qualifier("encoder2") private PasswordEncoder passwordEncoder; encoder1 이 @Primary 여도 @Qualifier("encoder2") 가 지정되어 있으면 encoder2 가 선택된다. 정리 같은 타입 Bean 여러 개 ↓ @Primary → 기본으로 사용할 Bean 지정 ↓ @Qualifier → 특정 Bean을 직접 지정 ↓ 둘 다 있으면 @Qualifier가 우선 3. 의존성 주입과 Bean 이름 @Autowired 는 기본적으로 타입(Type)을 기준으로 Bean을 찾는다. 예를 들어: @Autowired private PasswordEncoder passwordEncoder; Spring은 PasswordEncoder 타입의 Bean을 찾는다. 같은 타입의 Bean이 여러 개라면 @Qualifier , @Primary 등을 통해 대상을 결정한다. "타입으로 연결되지 않으면 무조건 Bean 이름으로 찾는다"라고 단순하게 이해하기보다는, 타입 기반 주입에서 후보가 여러 개일 경우 @Primary , @Qualifier 등의 규칙으로 대상을 결정한다 고 이해하는 것이 정확하다. 4. 인증(Authentication)과 인가(Authorization) 웹 애플리케이션의 보안에서 가장 기본적인 개념이다. 인증(Authentication) "당신이 누구인지 확인하는 것" 사용자가 실제로 주장하는 계정의 주인이 맞는지 확인한다. 예: 아이디 + 비밀번호 ↓ 로그인 ↓ 사용자 인증 예를 들어: user@example.com password123 을 입력했을 때 DB의 사용자 정보와 비교하여 해당 사용자가 누구인지 확인한다. 인가(Authorization) "당신이 이 작업을 할 권한이 있는지 확인하는 것" 인증이 끝난 후 특정 리소스에 접근할 권한이 있는지 판단한다. 예: 일반 사용자 → 일반 사용자 페이지 접근 가능 관리자 → 관리자 페이지 접근 가능 또는: GET /users/me → 일반 사용자 가능 DELETE /users/123 → 관리자만 가능 핵심 차이 인증 = 누구인가? 인가 = 무엇을 할 수 있는가? 5. HTTP Request와 Response HTTP는 클라이언트와 서버가 통신하기 위한 프로토콜이다. Request 클라이언트가 서버에 보내는 요청이다. Client ↓ HTTP Request ↓ Server 예: POST /login Content-Type: application/json { "username": "test", "password": "1234" } Response 서버가 클라이언트에게 보내는 응답이다. Client ↑ HTTP Response ↑ Server 예: HTTP/1.1 200 OK { "message": "로그인 성공" } 6. 쿠키(Cookie)와 세션(Session) 쿠키 쿠키는 클라이언트 측에 저장되는 작은 데이터 이다. 서버가 응답할 때 쿠키를 설정할 수 있다. Server ↓ Set-Cookie ↓ Browser 브라우저는 이후 요청에 해당 쿠키를 포함할 수 있다. Browser ↓ Cookie Server 쿠키 자체는 인증 방식이라기보다는 클라이언트에 데이터를 저장하고 HTTP 요청에 함께 전달하기 위한 메커니즘 이다. 세션 세션은 일반적으로 서버 측에서 클라이언트의 상태를 유지하기 위한 방법 이다. 예: 로그인 ↓ 서버에서 세션 생성 ↓ 세션 ID 발급 ↓ 클라이언트의 Cookie에 세션 ID 저장 이후 요청: Client ↓ Cookie: SESSION_ID=abc123 ↓ Server ↓ 세션 저장소에서 abc123 조회 ↓ 사용자 확인 따라서 흔히 사용하는 쿠키 + 세션 인증 구조에서는: Cookie = 클라이언트가 가지고 있는 세션 ID Session = 서버가 관리하는 인증 상태 라고 이해하면 좋다. 7. JWT JWT는 JSON Web Token 의 약자로, JSON 형태의 데이터를 기반으로 사용자 정보를 전달하는 토큰 방식이다. JWT는 크게 세 부분으로 구성된다. Header.Payload.Signature 예: xxxxx.yyyyy.zzzzz JWT의 특징 JWT의 Payload에는 Claim이라는 정보를 저장할 수 있다. 예: { "sub": "123", "username": "test", "role": "USER" } 중요한 점 JWT의 Payload는 암호화되어 있는 것이 아니다. 따라서 JWT를 가지고 있는 사람은 Payload를 디코딩하여 내용을 확인할 수 있다. JWT ↓ Base64URL 디코딩 ↓ Payload 확인 가능 따라서 비밀번호 같은 민감한 정보를 JWT Payload에 넣으면 안 된다. 8. JWT의 Signature JWT의 마지막 부분에는 Signature가 있다. Header.Payload.Signature 서버는 Secret Key 등을 이용하여 Signature를 생성한다. Header + Payload + Secret Key ↓ Signature 클라이언트가 JWT를 서버에 전달하면 서버는 Signature를 검증한다. 이를 통해 JWT가 서버가 발급한 정상적인 토큰인지, 내용이 변조되지 않았는지를 확인할 수 있다. 중요한 점 JWT는 누구나 읽을 수 있지만 임의로 수정해서 정상적인 JWT처럼 사용할 수 있는 것은 아니다. Secret Key가 노출되면 공격자가 정상적인 Signature를 생성할 수 있기 때문에 Secret Key는 반드시 안전하게 관리해야 한다. 9. JWT 인증 흐름 일반적인 JWT 인증 과정: [로그인] Client ↓ 아이디 + 비밀번호 ↓ Server ↓ 사용자 인증 ↓ JWT 발급 ↓ Client 이후 API 요청: Client ↓ Authorization: Bearer JWT ↓ Server ↓ JWT 검증 ↓ 사용자 식별 ↓ API 처리 JWT를 사용할 경우 서버가 매 요청마다 세션 저장소에서 로그인 상태를 조회하지 않아도 JWT 자체의 정보를 검증하여 사용자를 식별할 수 있다. 10. Filter Filter는 웹 애플리케이션에서 HTTP 요청과 응답을 처리하는 중간 단계 에 위치한다. 흐름을 단순화하면: Client ↓ Filter ↓ Controller ↓ Service ↓ Repository ↓ DB 응답은 반대로 돌아간다. DB ↓ Repository ↓ Service ↓ Controller ↓ Filter ↓ Client Filter에서는 요청을 가로채어 필요한 작업을 수행할 수 있다. 예: JWT 검증 인증 처리 요청/응답 로깅 인코딩 처리 공통 보안 처리 Spring Security에서도 Filter를 기반으로 인증 및 보안 처리를 수행한다. 11. Spring Security Spring Security는 Spring 애플리케이션에서 인증(Authentication)과 인가(Authorization), 보안 기능을 제공하는 프레임워크 이다. 대표적으로: 로그인 인증 비밀번호 처리 JWT 인증 권한 검사 URL 접근 제어 CSRF 방어 Security Filter Chain 등의 기능을 제공한다. 핵심 구조 Spring Security에서는 여러 Security Filter가 연결된 형태로 요청을 처리한다. Client Request ↓ Security Filter Chain ↓ 인증 / 권한 검사 ↓ Controller JWT 인증에서도 일반적으로 Filter에서 JWT를 확인하고 인증 객체를 SecurityContext에 등록하는 방식으로 구현한다. 12. Validation 사용자가 입력한 데이터가 올바른 형식인지 검증하는 기능이다. 예: public class SignupRequestDto { @NotBlank private String username; @Email private String email; @Size(min = 8) private String password; } 그리고 Controller에서: @PostMapping("/signup") public ResponseEntity<?> signup( @Valid @RequestBody SignupRequestDto request ) { ... } @Valid @Valid 는 해당 객체에 대해 Bean Validation을 수행하도록 하는 역할 을 한다. @Valid @RequestBody SignupRequestDto request 여기서 DTO에 선언된: @NotBlank @Email @Size @Pattern 등의 조건을 검사한다. 예: email = "hello" ↓ @Email 검사 ↓ 유효하지 않음 ↓ Validation 예외 발생 정리 DTO ↓ @NotBlank @Email @Size @Pattern ↓ @Valid ↓ Bean Validation 실행 13. Entity 연관관계 JPA에서는 Entity 사이의 관계를 표현할 수 있다. 대표적으로: 1 : 1 1 : N N : 1 N : M 이 있다. 13.1 1 : 1 관계 한 Entity가 다른 하나의 Entity와 연결되는 관계이다. 예: User 1 ─── 1 Profile 사용자 한 명당 프로필 하나가 존재한다고 가정할 수 있다. @OneToOne private Profile profile; 단방향 한쪽 Entity만 다른 Entity를 알고 있는 관계이다. User → Profile User에서는 Profile을 조회할 수 있지만 Profile에서는 User를 직접 참조하지 않는다. 양방향 양쪽 Entity가 서로를 참조한다. User ↔ Profile 양방향 관계에서는 연관관계의 주인(owner)을 정해야 한다. 14. 1 : N / N : 1 관계 실무에서 가장 자주 사용하는 관계 중 하나이다. 예: User 1 ───── N Post 사용자 한 명이 여러 개의 게시글을 작성할 수 있다. User ├── Post 1 ├── Post 2 └── Post 3 Entity 관점에서는 보통: // User @OneToMany private List<Post> posts; // Post @ManyToOne private User user; 이런 형태가 된다. 여기서 실제 DB의 외래 키는 일반적으로 N 쪽인 Post 테이블 에 위치한다. post ---------------- id title user_id ← FK 따라서 DB 관점에서는: User 1 ←── N Post 이다. 15. N : M 관계 여러 Entity가 여러 Entity와 연결되는 관계이다. 예: 학생 N ───── M 강의 학생 한 명이 여러 강의를 수강할 수 있고, 강의 하나에도 여러 학생이 수강할 수 있다. 관계형 DB에서는 일반적으로 중간 테이블을 사용한다. Student ↓ StudentCourse ↑ Course 예: student course student_course student_course 가 중간 테이블 역할을 한다. 실무에서는 단순한 @ManyToMany 보다는 중간 Entity를 직접 만들어 관리하는 방식 이 더 유연한 경우가 많다. 예: Student ↓ Enrollment ↓ Course Enrollment에 다음과 같은 추가 정보를 넣을 수도 있다. 수강일 수강상태 점수 16. 영속성 컨텍스트(Persistence Context) JPA를 이해할 때 중요한 개념이다. 영속성 컨텍스트는 쉽게 말하면 JPA가 Entity를 관리하는 공간 이라고 이해할 수 있다. Entity ↓ Persistence Context ↓ DB Entity가 영속성 컨텍스트에서 관리되면 JPA는 Entity의 상태를 추적할 수 있다. 17. Dirty Checking 영속 상태의 Entity가 변경되었을 때 JPA가 변경 내용을 감지하여 DB에 반영하는 기능이다. 예: @Transactional public void updateUsername(Long id, String username) { User user = userRepository.findById(id) .orElseThrow(); user.setUsername(username); } 여기서는 명시적으로: userRepository.save(user); 를 호출하지 않아도 Transaction이 정상적으로 종료될 때 변경 사항이 DB에 반영될 수 있다. 왜냐하면: Entity 조회 ↓ 영속성 컨텍스트에서 관리 ↓ Entity 값 변경 ↓ Dirty Checking ↓ UPDATE SQL 생성 ↓ DB 반영 이 과정이 수행되기 때문이다. 18. @Transactional과 영속성 컨텍스트 @Transactional 은 하나의 작업을 하나의 트랜잭션으로 묶어주는 기능 이다. Spring에서 JPA를 사용할 때 일반적으로 Transaction 범위 안에서 영속성 컨텍스트가 관리된다. 특히 Dirty Checking을 이용한 변경 작업 에서는 Transaction이 중요하다. @Transactional public void updateUser(...) { User user = repository.findById(id) .orElseThrow(); user.setName("변경된 이름"); } Transaction이 시작되면서 Entity가 영속 상태로 관리되고, 메서드가 정상적으로 종료되면 변경 사항을 감지하여 DB에 반영한다. 중요한 구분 @Transactional ↓ Transaction 시작 ↓ 영속성 컨텍스트에서 Entity 관리 ↓ Entity 변경 ↓ Dirty Checking ↓ Transaction Commit ↓ DB 반영 다만 "Transactional이 없으면 영속성 컨텍스트가 무조건 존재하지 않는다" 라고 단순하게 이해하면 안 된다. 조회 자체는 Repository 메서드 내부에서 Transaction이 처리되는 경우도 있기 때문이다. 중요한 것은 Entity를 변경하고 Dirty Checking으로 DB에 반영하려는 작업은 적절한 Transaction 범위가 필요하다 는 것이다. 19. 오늘 내용 핵심 요약 Bean Spring Container가 관리하는 객체 같은 타입 Bean 여러 개 ↓ @Primary → 기본 Bean @Qualifier → 특정 Bean 지정 ↓ Qualifier가 더 우선 인증 / 인가 인증 = 누구인가? 인가 = 무엇을 할 수 있는가? Cookie / Session Cookie → 클라이언트에 저장되는 작은 데이터 Session → 서버 측에서 사용자 상태를 관리 JWT Header.Payload.Signature Payload → 누구나 읽을 수 있음 Signature → Secret Key를 이용해 변조 여부 검증 Secret Key → 절대 외부에 노출하면 안 됨 Filter Client ↓ Filter ↓ Controller 요청/응답을 중간에서 처리할 수 있다. Validation @NotBlank @Email @Size @Pattern ↓ @Valid ↓ Bean Validation JPA Entity ↓ Persistence Context ↓ Dirty Checking ↓ Transaction Commit ↓ DB Entity 관계 1 : 1 1 : N N : 1 N : M 특히 실무에서는 1:N / N:1 관계를 가장 많이 접하게 되고, N:M은 중간 Entity를 두어 풀어내는 경우가 많다. 개념 요약 Bean Bean은 Spring Container가 생성하고 관리하는 객체이며, @Bean 이나 Component Scan 등을 통해 등록할 수 있습니다. @Primary / @Qualifier 같은 타입의 Bean이 여러 개 있을 경우 @Primary 는 기본 Bean을 지정하고, @Qualifier 는 특정 Bean을 명시적으로 선택하며 @Qualifier 가 더 높은 우선순위를 가집니다. 인증 / 인가 인증은 사용자가 누구인지 확인하는 과정이고, 인가는 인증된 사용자가 특정 리소스에 접근할 권한이 있는지 확인하는 과정입니다. JWT JWT는 Header, Payload, Signature로 구성된 토큰이며 Payload는 누구나 읽을 수 있기 때문에 민감한 정보를 저장하면 안 되고, Secret Key를 이용한 Signature 검증으로 토큰의 변조 여부를 확인합니다. Filter Filter는 Controller보다 앞단에서 HTTP 요청과 응답을 가로채 공통 처리를 할 수 있는 기능이며, Spring Security에서는 인증과 인가 같은 보안 처리를 위해 Filter Chain을 사용합니다. @Valid @Valid 는 DTO에 선언된 Bean Validation 조건을 검사하도록 하며 @NotBlank , @Email , @Size 등의 검증 어노테이션과 함께 사용합니다. Dirty Checking JPA에서 영속성 컨텍스트가 관리하는 Entity의 변경 사항을 감지하여 Transaction이 Commit될 때 변경된 내용을 DB에 반영하는 기능입니다. 한 줄 회고 JWT와 Spring Security를 이용한 회원가입 및 로그인 로직을 공부하면서, 사용자 정보를 직접 다루는 만큼 인증·인가 과정과 예외 처리 등 고려해야 할 부분이 많다는 것을 알게 되었다. 단순히 동작하는 코드를 작성하는 것에 그치지 않고, 각 로직이 왜 필요한지와 예외 상황에서 어떻게 동작하는지까지 확실하게 이해하고 넘어가야겠다는 생각이 들었다. 또한 JPA Entity의 관계인 일대일(1:1), 일대다(1:N), 다대일(N:1), 다대다(N:M)의 개념과 기본적인 사용 방법을 이해할 수 있었다. 다만 Entity 간의 관계가 실제 데이터베이스에서 어떤 방식으로 표현되는지,
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
[TIL] Spring 핵심 개념 정리: Bean 주입, Security, JWT부터 JPA 연관관계까지. Spring 핵심 개념 정리 1. Bean 수동 등록 Spring에서 객체를 Bean으로 등록하는 방법에는 크게 컴포넌트 스캔을 이용한 자동 등록 과 @Bean 을 이용한 수동 등록 이 있다. 수동 등록 대표적으로 직접 생성하기 어려운 객체나 라이브러리 객체를 Bean으로 등록할 때 사용한다. @Configuration public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } 이렇게 등록하면 Spring Container가…
Open source