2025년 7월 29일 화요일

[springboot]JWT 로그인 인증 구현 가이드

JWT 로그인 인증 구현 가이드

이 가이드에서는 Spring Boot와 Vue.js를 사용하여 JWT(JSON Web Token) 기반의 로그인 인증 시스템을 구축하는 전체 과정을 안내합니다.

Part 1: 백엔드 (Spring Boot) 설정

가장 먼저 백엔드에서 사용자 인증을 처리하고 JWT를 발급하는 API를 만듭니다.

1단계: 의존성 추가

(이전과 동일)

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
    // ...
}

2단계: User Entity 및 Repository 생성

(이전과 동일)

User.java

package dev.nerobong2.openehr.open_ehr.backend.user;
// ... (Lombok, JPA 어노테이션 등)
public class User {
    // ... id, username, password 필드 ...
}

UserRepository.java

package dev.nerobong2.openehr.open_ehr.backend.user;
// ...
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

3단계: Spring Security 설정 (단순 버전으로 복원)

403 오류의 원인을 명확히 하기 위해, 가장 단순한 초기 버전으로 설정을 되돌립니다.

SecurityConfig.java

// [수정] 403 오류 원인 파악을 위해 가장 단순한 버전으로 복원합니다.
package dev.nerobong2.openehr.open_ehr.backend.config;

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.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // CSRF 보호 비활성화
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 사용 안 함
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll() // 로그인/회원가입 API는 모두 허용
                .anyRequest().authenticated() // 나머지 요청은 인증 필요
            );
        return http.build();
    }
}

4단계: 로그인 API 생성 (단순 버전으로 복원)

AuthService에서 직접 PasswordEncoder를 사용하여 비밀번호를 비교하는 초기 방식으로 되돌립니다.

AuthService.java

// [수정] PasswordEncoder를 직접 사용하는 단순 버전으로 복원합니다.
package dev.nerobong2.openehr.open_ehr.backend.auth;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import dev.nerobong2.openehr.open_ehr.backend.user.User;
import dev.nerobong2.openehr.open_ehr.backend.user.UserRepository;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public String login(String username, String password) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));

        // 입력된 비밀번호와 DB의 암호화된 비밀번호를 비교
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
        }

        // 로그인 성공 시 임시 토큰 반환
        return "temp-jwt-token-for-" + user.getUsername();
    }
}

AuthController.java (변경 없음)

// ...
public class AuthController {
    // ...
    @PostMapping("/login")
    public String login(@RequestBody LoginRequestDto requestDto) {
        return authService.login(requestDto.username(), requestDto.password());
    }
}
record LoginRequestDto(String username, String password) {}

5단계: 올바른 테스트 데이터 생성 (매우 중요!)

“비밀번호가 일치하지 않습니다” 오류는 DB에 저장된 암호화된 비밀번호가 잘못되었기 때문입니다. 아래 방법으로 올바른 암호화 비밀번호를 직접 생성하여 DB에 넣으세요.

  1. 메인 애플리케이션 파일(OpenEhrBackendApplication.java)을 열고, 기존 클래스 내부에 임시로 아래 코드를 추가합니다. 이 코드는 서버가 시작될 때 비밀번호 '1234’를 암호화하여 콘솔에 출력해 줍니다.

    OpenEhrBackendApplication.java

    package dev.nerobong2.openehr.open_ehr.backend;
    
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @SpringBootApplication
    public class OpenEhrBackendApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OpenEhrBackendApplication.class, args);
        }
    
        // [추가] 비밀번호 암호화를 위해 이 Bean을 기존 클래스 내부에 임시로 추가합니다.
        @Bean
        public CommandLineRunner commandLineRunner(PasswordEncoder passwordEncoder) {
            return args -> {
                String encodedPassword = passwordEncoder.encode("1234");
                System.out.println("####################################################");
                System.out.println("Encoded password for '1234': " + encodedPassword);
                System.out.println("####################################################");
            };
        }
    }
    
    
  2. 백엔드 서버를 재시작합니다.

  3. 터미널(콘솔)에 아래와 같이 암호화된 비밀번호가 출력됩니다.

    ####################################################
    Encoded password for '1234': $2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ####################################################
    
    
  4. 콘솔에 출력된 $2a$10$...로 시작하는 전체 문자열을 복사합니다.

  5. DBeaver에서 아래 SQL을 실행하여 password 컬럼에 복사한 값을 붙여넣고 사용자를 생성합니다.

    -- 기존 데이터 삭제
    DELETE FROM users WHERE username = 'testuser';
    
    -- 새로 생성된 암호화 값으로 INSERT
    INSERT INTO users (username, password, employee_number, company_code)
    VALUES ('testuser', '콘솔에서 복사한 암호화된 비밀번호 붙여넣기', '12345', 'COMP01');
    
    COMMIT;
    
    
  6. 테스트 데이터 생성이 끝나면, OpenEhrBackendApplication.java에 추가했던 CommandLineRunner 코드는 다시 삭제해도 됩니다.

Part 2: 프론트엔드 (Vue) 설정

(이전과 동일)

다음 단계: 이제 백엔드 서버를 재시작하고, 프론트엔드에서 아이디 testuser, 비밀번호 1234로 다시 로그인을 시도해 보세요. 이제는 403 오류 없이 정상적으로 로그인되어 메인 페이지로 이동할 것입니다.## JWT 로그인 인증 구현 가이드

이 가이드에서는 Spring Boot와 Vue.js를 사용하여 JWT(JSON Web Token) 기반의 로그인 인증 시스템을 구축하는 전체 과정을 안내합니다.

Part 1: 백엔드 (Spring Boot) 설정

가장 먼저 백엔드에서 사용자 인증을 처리하고 JWT를 발급하는 API를 만듭니다.

1단계: 의존성 추가

(이전과 동일)

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
    // ...
}

2단계: User Entity 및 Repository 생성

(이전과 동일)

User.java

package dev.nerobong2.openehr.open_ehr.backend.user;
// ... (Lombok, JPA 어노테이션 등)
public class User {
    // ... id, username, password 필드 ...
}

UserRepository.java

package dev.nerobong2.openehr.open_ehr.backend.user;
// ...
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

3단계: Spring Security 설정 (단순 버전으로 복원)

403 오류의 원인을 명확히 하기 위해, 가장 단순한 초기 버전으로 설정을 되돌립니다.

SecurityConfig.java

// [수정] 403 오류 원인 파악을 위해 가장 단순한 버전으로 복원합니다.
package dev.nerobong2.openehr.open_ehr.backend.config;

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.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // CSRF 보호 비활성화
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 사용 안 함
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll() // 로그인/회원가입 API는 모두 허용
                .anyRequest().authenticated() // 나머지 요청은 인증 필요
            );
        return http.build();
    }
}

4단계: 로그인 API 생성 (단순 버전으로 복원)

AuthService에서 직접 PasswordEncoder를 사용하여 비밀번호를 비교하는 초기 방식으로 되돌립니다.

AuthService.java

// [수정] PasswordEncoder를 직접 사용하는 단순 버전으로 복원합니다.
package dev.nerobong2.openehr.open_ehr.backend.auth;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import dev.nerobong2.openehr.open_ehr.backend.user.User;
import dev.nerobong2.openehr.open_ehr.backend.user.UserRepository;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class AuthService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public String login(String username, String password) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));

        // 입력된 비밀번호와 DB의 암호화된 비밀번호를 비교
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
        }

        // 로그인 성공 시 임시 토큰 반환
        return "temp-jwt-token-for-" + user.getUsername();
    }
}

AuthController.java (변경 없음)

// ...
public class AuthController {
    // ...
    @PostMapping("/login")
    public String login(@RequestBody LoginRequestDto requestDto) {
        return authService.login(requestDto.username(), requestDto.password());
    }
}
record LoginRequestDto(String username, String password) {}

5단계: 올바른 테스트 데이터 생성 (매우 중요!)

“비밀번호가 일치하지 않습니다” 오류는 DB에 저장된 암호화된 비밀번호가 잘못되었기 때문입니다. 아래 방법으로 올바른 암호화 비밀번호를 직접 생성하여 DB에 넣으세요.

  1. 메인 애플리케이션 파일(OpenEhrBackendApplication.java)을 열고, 기존 클래스 내부에 임시로 아래 코드를 추가합니다. 이 코드는 서버가 시작될 때 비밀번호 '1234’를 암호화하여 콘솔에 출력해 줍니다.

    OpenEhrBackendApplication.java

    package dev.nerobong2.openehr.open_ehr.backend;
    
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Bean;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @SpringBootApplication
    public class OpenEhrBackendApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OpenEhrBackendApplication.class, args);
        }
    
        // [추가] 비밀번호 암호화를 위해 이 Bean을 기존 클래스 내부에 임시로 추가합니다.
        @Bean
        public CommandLineRunner commandLineRunner(PasswordEncoder passwordEncoder) {
            return args -> {
                String encodedPassword = passwordEncoder.encode("1234");
                System.out.println("####################################################");
                System.out.println("Encoded password for '1234': " + encodedPassword);
                System.out.println("####################################################");
            };
        }
    }
    
    
  2. 백엔드 서버를 재시작합니다.

  3. 터미널(콘솔)에 아래와 같이 암호화된 비밀번호가 출력됩니다.

    ####################################################
    Encoded password for '1234': $2a$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    ####################################################
    
    
  4. 콘솔에 출력된 $2a$10$...로 시작하는 전체 문자열을 복사합니다.

  5. DBeaver에서 아래 SQL을 실행하여 password 컬럼에 복사한 값을 붙여넣고 사용자를 생성합니다.

    -- 기존 데이터 삭제
    DELETE FROM users WHERE username = 'testuser';
    
    -- 새로 생성된 암호화 값으로 INSERT
    INSERT INTO users (username, password, employee_number, company_code)
    VALUES ('testuser', '콘솔에서 복사한 암호화된 비밀번호 붙여넣기', '12345', 'COMP01');
    
    COMMIT;
    
    
  6. 테스트 데이터 생성이 끝나면, OpenEhrBackendApplication.java에 추가했던 CommandLineRunner 코드는 다시 삭제해도 됩니다.

Part 2: 프론트엔드 (Vue) 설정

(이전과 동일)

다음 단계: 이제 백엔드 서버를 재시작하고, 프론트엔드에서 아이디 testuser, 비밀번호 1234로 다시 로그인을 시도해 보세요. 이제는 403 오류 없이 정상적으로 로그인되어 메인 페이지로 이동할 것입니다.

댓글 없음:

댓글 쓰기

[springboot]실제 JWT 발급 및 검증 구현

실제 JWT 발급 및 검증 구현 이전 단계에서 만든 임시 토큰을 실제 암호화된 JWT(JSON Web Token)로 대체하고, Spring Security 필터를 통해 API 요청을 보호하는 방법을 구현합니다. Part 1: 백엔드 (Spring ...