2025년 12월 21일 일요일

[OS]리눅스서버 WAS 관련 권한 관리

[Best Practice] Linux 서버 WAS 권한 체계 구축 가이드

리눅스 환경에서 다수의 운영자가 WAS(Tomcat, Nginx 등)를 공동 관리할 때 발생하는 권한 꼬임(Permission Denied) 문제를 방지하기 위한 표준 설정법입니다.


1. 계정 및 그룹 설계 (Account & Group)

리눅스는 ‘1파일 1그룹’ 원칙을 가지므로, 모든 관리자를 하나의 **보조 그룹(Secondary Group)**으로 묶는 전략이 필수입니다.

🛠 터미널(Terminal) 명령어

Bash

# 1. WAS 관리 전용 그룹 생성
sudo groupadd webadmin

# 2. 서비스 구동용 시스템 계정 생성 (로그인 불가 설정으로 보안 강화)
sudo useradd -r -s /usr/sbin/nologin wasuser

# 3. 관리자 계정(aaaa, bbbb)을 관리 그룹에 추가 (보조 그룹 추가 옵션 -aG)
sudo usermod -aG webadmin aaaa
sudo usermod -aG webadmin bbbb
sudo usermod -aG webadmin wasuser  # 서비스 계정도 그룹에 포함


2. 폴더 소유권 및 특수 권한 설정 (Ownership & SetGID)

리눅스에는 윈도우식 상속이 없으므로, SetGID라는 특수 권한을 사용하여 새로 생성되는 파일의 그룹 소유권을 강제로 고정합니다.

🛠 설정 절차

  1. 디렉토리 소유권 변경:

    Bash

    # /app/was 폴더의 소유자를 wasuser로, 그룹을 webadmin으로 일괄 변경
    sudo chown -R wasuser:webadmin /app/was
    
    
  2. 기본 권한 부여:

    Bash

    # 소유자와 그룹 멤버에게 읽기/쓰기/실행 권한 부여 (775)
    sudo chmod -R 775 /app/was
    
    
  3. SetGID 설정 (리눅스 상속의 핵심):

    Bash

    # 하위 디렉토리에 SetGID를 걸어, 누가 파일을 만들어도 그룹이 'webadmin'으로 고정되게 함
    find /app/was -type d -exec chmod g+s {} +
    
    

3. 서비스 구성 (Systemd Service)

시스템 부팅 시 WAS가 지정된 계정으로 자동 실행되도록 systemd 서비스 파일을 설정합니다.

🛠 서비스 파일 예시 (/etc/systemd/system/tomcat.service)

Ini, TOML

[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking

# 핵심 설정: 서비스를 구동할 사용자 및 그룹 명시
User=wasuser
Group=webadmin

Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ExecStart=/app/was/tomcat/bin/startup.sh
ExecStop=/app/was/tomcat/bin/shutdown.sh

[Install]
WantedBy=multi-user.target


4. 💡 실무 핵심 요약 (Cheat Sheet)

항목

설정 권장 사항 (Best Practice)

이유

그룹 관리

모든 관리자를 보조 그룹(webadmin)에 포함

다수의 사용자가 동일한 파일 수정 가능

상속 구현

폴더에 SetGID(g+s) 권한 부여

신규 생성 파일의 그룹 소유권 자동 고정

파일 생성값

umask 값 확인 (기본 002 권한 권장)

그룹 멤버에게 쓰기 권한이 자동으로 생기도록 함

권한 적용

그룹 추가 후 로그아웃 & 로그인 필수

세션이 갱신되어야 새로운 그룹 권한이 반영됨


⚠️ 주의사항

  • umask 설정: 시스템의 umask022로 되어 있으면 그룹 멤버에게 쓰기 권한이 없습니다. 그룹 협업이 잦은 WAS 폴더 내에서는 umask 002를 권장합니다.

  • 파일 vs 폴더: chmod g+s는 반드시 디렉토리에만 적용하는 것이 보안상 안전합니다. (find 명령어 활용 권장)


[OS]윈도우서버 WAS 관련 권한관리

[Best Practice] Windows 서버 WAS 권한 체계 구축 가이드

Windows 환경에서 WAS(Tomcat, JBoss, IIS 등)를 안정적으로 운영하기 위해 **‘소유권 분쟁’**과 ‘액세스 거부’ 에러를 원천 차단하는 표준 보안 설정법입니다.


1. 계정 및 그룹 설계 (Account Design)

개인 계정이 아닌 서비스 전용 계정권한 관리용 그룹을 분리하여 관리 효율성과 보안성을 동시에 확보합니다.

🛠 관리자 명령 프롬프트(CMD) 명령어

DOS

:: 1. WAS 관리 전용 로컬 그룹 생성
net localgroup WAS_Managers /add

:: 2. 서비스 구동용 계정 생성 (일반 사용자 권한)
:: /passwordchg:no 옵션으로 서비스 중단 방지
net user svc_was P@ssword123 /add /comment:"WAS Service Account" /passwordchg:no

:: 3. 관리용 그룹에 멤버 추가 (서비스 계정 + 실제 운영자들)
net localgroup WAS_Managers svc_was /add
net localgroup WAS_Managers aaaa /add
net localgroup WAS_Managers bbbb /add


2. 폴더 권한 및 상속 설정 (ACL & Inheritance)

Windows 보안의 핵심인 **‘권한 상속’**을 활용하여, 서버 구동 중 생성되는 로그나 임시 파일이 소유권 문제로 인해 삭제/수정되지 않는 상황을 방지합니다.

🛠 설정 절차 (GUI 중심)

  1. 루트 폴더 생성: C:\was (모든 WAS 인스턴스의 부모 경로)

  2. 보안 속성 진입: C:\was 우클릭 → [속성][보안] 탭 → [고급] 클릭

  3. 권한 부여:

    • [추가] 클릭 → [보안 주체 선택]WAS_Managers 입력 후 확인

    • 권한: 모든 권한 또는 수정(Modify) 체크

    • 적용 대상: 이 폴더, 하위 폴더 및 파일 선택

  4. 상속 강제 적용 (가장 중요):

    • 창 하단의 [모든 자식 개체 사용 권한 항목을 이 개체의 상속 가능한 사용 권한 항목으로 바꾸기] 체크

    • [확인]을 눌러 하위의 모든 tomcat, logs 폴더에 권한을 일괄 전파


3. 서비스 로그온 권한 부여 (Service Logon Right)

생성한 svc_was 계정이 일반 사용자 권한임에도 불구하고 시스템 서비스를 구동할 수 있도록 권한을 승인합니다.

🛠 로컬 보안 정책 설정

  1. Win + Rsecpol.msc 실행

  2. 로컬 정책사용자 권한 할당 이동

  3. [서비스로 로그온] 항목 더블 클릭

  4. svc_was 계정을 명단에 추가 후 확인


4. WAS 서비스 실행 설정 (Service Configuration)

이제 실제 등록된 서비스를 특정 계정으로 구동하도록 연결합니다.

  1. services.msc 실행 → 해당 WAS 서비스(예: Tomcat) 우클릭 → [속성]

  2. [로그온] 탭 클릭 → [다음 계정으로 지정] 선택

  3. svc_was 계정과 비밀번호 입력 후 서비스 재시작


💡 실무 핵심 요약 (Cheat Sheet)

항목

설정 권장 사항 (Best Practice)

이유

권한 주체

개인 계정이 아닌 전용 그룹에 부여

멤버 교체 시 폴더 권한 수정 불필요

상속 설정

부모 폴더에서 상속 강제 적용

새로 생성되는 로그 파일의 접근권 보장

계정 권한

서비스 계정은 Standard User 유지

해킹 시 시스템 전체 장악 방지 (최소 권한)

수동 실행

관리자가 직접 실행 시 그룹 추가 필수

그룹 추가 후에는 반드시 재로그인 필요


2025년 7월 30일 수요일

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

실제 JWT 발급 및 검증 구현

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

Part 1: 백엔드 (Spring Boot) JWT 로직 구현

1단계: JWT Secret Key 설정

[수정] JWT 라이브러리의 보안 요구사항(256비트 이상)을 만족하는 더 길고 안전한 Secret Key 예시로 변경합니다.

backend/src/main/resources/application.properties 파일에 아래 내용을 추가합니다.

# JWT Secret Key 설정
# 256비트 이상의 길이를 가진 Base64 인코딩된 문자열이어야 합니다.
# 아래는 예시이며, 실제 운영 환경에서는 openssl rand -base64 32 명령 등으로 생성한 키를 사용하세요.
jwt.secret=256비트보타작은키는 오류

2단계: JWT 유틸리티 클래스 생성

JwtUtil.java

package dev.nerobong2.openehr.open_ehr.backend.jwt;
// ... (이전과 동일한 코드)

3단계: AuthService 수정

AuthService.java

package dev.nerobong2.openehr.open_ehr.backend.auth;

import dev.nerobong2.openehr.open_ehr.backend.jwt.JwtUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class AuthService {

    private final AuthenticationManager authenticationManager;
    private final JwtUtil jwtUtil;

    public String login(String username, String password) {
        // Spring Security를 통해 인증 시도
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(username, password)
        );

        // 인증 성공 시 UserDetails 객체를 가져와 JWT 생성
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        return jwtUtil.generateToken(userDetails);
    }
}

4단계: JWT 인증 필터 생성

JwtAuthFilter.java

package dev.nerobong2.openehr.open_ehr.backend.jwt;
// ... (이전과 동일한 코드)

5단계: SecurityConfig와 ApplicationConfig 분리

ApplicationConfig.java

package dev.nerobong2.openehr.open_ehr.backend.config;

import dev.nerobong2.openehr.open_ehr.backend.user.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.ArrayList;

@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {

    private final UserRepository userRepository;

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> userRepository.findByUsername(username)
                .map(user -> new org.springframework.security.core.userdetails.User(
                        user.getUsername(),
                        user.getPassword(),
                        new ArrayList<>()))
                .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username));
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

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

SecurityConfig.java

package dev.nerobong2.openehr.open_ehr.backend.config;

import dev.nerobong2.openehr.open_ehr.backend.jwt.JwtAuthFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtAuthFilter jwtAuthFilter;
    private final AuthenticationProvider authenticationProvider;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
            )
            .authenticationProvider(authenticationProvider)
            .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

6단계: 인증 테스트용 API 생성

TestController.java

package dev.nerobong2.openehr.open_ehr.backend.test;
// ... (이전과 동일한 코드)

Part 2: 프론트엔드 (Vue) JWT 연동 및 테스트

(이전과 동일)

1단계: 상태 관리 (Pinia) 설정

frontend/src/stores/auth.ts

// ... (이전과 동일한 코드)

2단계: 인증된 API 호출 테스트

frontend/src/views/HomeView.vue

<script setup lang="ts">
// ... (이전과 동일한 코드)
</script>

<template>
  <main>
    <h1>메인 페이지</h1>
    <p>로그인에 성공했습니다.</p>
    <hr />
    <p><strong>{{ message }}</strong></p>
  </main>
</template>

다음 단계: 이제 백엔드 서버를 재시작하시면 오류 없이 정상적으로 실행될 것입니다. 그 후 다시 로그인을 테스트해 보세요.

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 오류 없이 정상적으로 로그인되어 메인 페이지로 이동할 것입니다.

2024년 10월 25일 금요일

[oracle]백업및 복구

[oracle]백업및 복구

오라클 덤프 백업및 복구

윈도우 서버 기반 간단 정리

--디렉터리 조회

sqlplus 또는 dbtool 입력시작

SELECT * FROM DBA_DIRECTORIES ;

--D:\DEV\DATABASE\ORACLE21C\ADMIN\XE\DPDUMP 경로에 작업할 dpump_dir1 디렉토리 생성 

CREATE DIRECTORY dpump_dir1 AS 'D:\DEV\DATABASE\ORACLE21C\ADMIN\XE\DPDUMP';

--dpump_dir1 디렉토리레 권한을 system 계정에 부여

GRANT READ, WRITE ON DIRECTORY dpump_dir1 TO system;

--시스템 계정의 비밀번호가 없다면 생성

ALTER USER system IDENTIFIED BY 1234;

sqlplus 또는 dbtool 입력 끝


cmd 입력 시작

-- cmd 창을 열어 dmp 생성

expdp c##nerobong2/1234@xe SCHEMAS=C##NEROBONG2 DIRECTORY=dpump_dir1 DUMPFILE=schema_backup2.dmp LOGFILE=schema_backup.log

--전체복원

impdp c##nerobong2/1234@xe FULL=Y DIRECTORY=dpump_dir1 DUMPFILE=schema_backup2.dmp LOGFILE=full_restore.log

--스키마 복원

impdp c##nerobong2/1234@xe SCHEMAS=C##NEROBONG2 DIRECTORY=dpump_dir1 DUMPFILE=schema_backup2.dmp LOGFILE=schema_restore.log

--테이블 복원
impdp c##nerobong2/1234@xe TABLES=C##NEROBONG2.SALE DIRECTORY=dpump_dir1 DUMPFILE=schema_backup2.dmp LOGFILE=table_restore.log


cmd 입력 끝

2024년 7월 30일 화요일

[lunux]리눅스 폴더별 용량 확인

리눅스 폴더별 용량 확인

조회 하고자 하는 디렉토리 리스트가있는 경로로 이동후

du -h --max-depth=1

[oracle]오라클 오류 조회

ORACLE DB 오류 조회

ORACLE 내부 오류 조회 관련 명령어

select name, value from v$diag_info;

SELECT * FROM DBA_ERRORS WHERE NAME = 'DB오브젝트명';

SELECT * FROM USER_ERRORS WHERE NAME = '%DB오브젝트명%';

[OS]리눅스서버 WAS 관련 권한 관리

[Best Practice] Linux 서버 WAS 권한 체계 구축 가이드 리눅스 환경에서 다수의 운영자가 WAS(Tomcat, Nginx 등)를 공동 관리할 때 발생하는 권한 꼬임(Permission Denied) 문제를 방지하기 위한 표준 설정...