[보안 설정 개선] JwtTokenIssuanceFilter 및 JwtTokenValidationFilter 추가로 JWT 인증 로직을 강화하고, SecurityPathConfig를 통해 허용 경로 설정을 외부화하여 보안 유연성 향상. JwtAccessDeniedHandler 및 JwtAuthenticationEntryPoint 삭제로 코드 정리.
This commit is contained in:
		@@ -2,10 +2,12 @@ package com.bio.bio_backend;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
			
		||||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
 | 
			
		||||
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
@EnableJpaAuditing
 | 
			
		||||
@EnableConfigurationProperties
 | 
			
		||||
public class BioBackendApplication {
 | 
			
		||||
 | 
			
		||||
	public static void main(String[] args) {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
package com.bio.bio_backend.global.config;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.context.properties.ConfigurationProperties;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
@ConfigurationProperties(prefix = "security")
 | 
			
		||||
public class SecurityPathConfig {
 | 
			
		||||
    
 | 
			
		||||
    private List<String> permitAllPaths;
 | 
			
		||||
    
 | 
			
		||||
    public List<String> getPermitAllPaths() {
 | 
			
		||||
        return permitAllPaths;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public void setPermitAllPaths(List<String> permitAllPaths) {
 | 
			
		||||
        this.permitAllPaths = permitAllPaths;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * 주어진 경로가 허용된 경로인지 확인
 | 
			
		||||
     * @param path 확인할 경로
 | 
			
		||||
     * @param contextPath 컨텍스트 경로
 | 
			
		||||
     * @return 허용 여부
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isPermittedPath(String path, String contextPath) {
 | 
			
		||||
        if (permitAllPaths == null) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return permitAllPaths.stream()
 | 
			
		||||
                .anyMatch(permittedPath -> {
 | 
			
		||||
                    String fullPath = contextPath + permittedPath;
 | 
			
		||||
                    if (permittedPath.endsWith("/**")) {
 | 
			
		||||
                        // /** 패턴 처리
 | 
			
		||||
                        String basePath = fullPath.substring(0, fullPath.length() - 2);
 | 
			
		||||
                        return path.startsWith(basePath);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return path.equals(fullPath);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
package com.bio.bio_backend.global.exception;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Qualifier;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.security.access.AccessDeniedException;
 | 
			
		||||
import org.springframework.security.web.access.AccessDeniedHandler;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.servlet.HandlerExceptionResolver;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.ServletException;
 | 
			
		||||
import jakarta.servlet.http.HttpServletRequest;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
			
		||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
 | 
			
		||||
    private final HandlerExceptionResolver resolver;
 | 
			
		||||
 | 
			
		||||
    public JwtAccessDeniedHandler(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
 | 
			
		||||
        this.resolver = resolver;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
 | 
			
		||||
 | 
			
		||||
        Exception exception = (Exception) request.getAttribute("exception");
 | 
			
		||||
 | 
			
		||||
        if (exception != null) {
 | 
			
		||||
            resolver.resolveException(request, response, null, exception);
 | 
			
		||||
        } else {
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
 | 
			
		||||
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
 | 
			
		||||
            new ObjectMapper().writeValue(response.getWriter(), ApiResponseDto.fail(ApiResponseCode.COMMON_FORBIDDEN));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
package com.bio.bio_backend.global.exception;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.ServletException;
 | 
			
		||||
import jakarta.servlet.http.HttpServletRequest;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Qualifier;
 | 
			
		||||
import org.springframework.security.core.AuthenticationException;
 | 
			
		||||
import org.springframework.security.web.AuthenticationEntryPoint;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.springframework.web.servlet.HandlerExceptionResolver;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
 | 
			
		||||
    private final HandlerExceptionResolver resolver;
 | 
			
		||||
 | 
			
		||||
    public JwtAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
 | 
			
		||||
        this.resolver = resolver;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
 | 
			
		||||
 | 
			
		||||
        Exception exception = (Exception) request.getAttribute("exception");
 | 
			
		||||
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
 | 
			
		||||
 | 
			
		||||
        if (exception == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        resolver.resolveException(request, response, null, exception);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.bio.bio_backend.global.security;
 | 
			
		||||
package com.bio.bio_backend.global.filter;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
import jakarta.servlet.FilterChain;
 | 
			
		||||
@@ -9,13 +9,11 @@ import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.dto.LoginRequestDto;
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.dto.LoginResponseDto;
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
 | 
			
		||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
 | 
			
		||||
import com.bio.bio_backend.global.utils.JwtUtils;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.SneakyThrows;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.security.authentication.AuthenticationManager;
 | 
			
		||||
@@ -30,36 +28,22 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
@RequiredArgsConstructor
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter {
 | 
			
		||||
 | 
			
		||||
    private final AuthenticationManager authenticationManager;
 | 
			
		||||
    private final MemberService memberService;
 | 
			
		||||
    private final JwtUtils jwtUtils;
 | 
			
		||||
    private final Environment env;
 | 
			
		||||
    private final ObjectMapper objectMapper;
 | 
			
		||||
 | 
			
		||||
    // 사용자 login 인증 처리
 | 
			
		||||
    @SneakyThrows
 | 
			
		||||
    @Override
 | 
			
		||||
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
 | 
			
		||||
            throws AuthenticationException {
 | 
			
		||||
 | 
			
		||||
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
 | 
			
		||||
        LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
 | 
			
		||||
 | 
			
		||||
//        UsernamePasswordAuthenticationToken authToken;
 | 
			
		||||
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(requestDto.getUserId(), requestDto.getPassword());
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        if (req.getLoginLogFlag() == 1) {
 | 
			
		||||
            authToken = new UsernamePasswordAuthenticationToken("admin2", "test123!"); // 비밀번호는 실제 비밀번호로 설정해야 함
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new AuthenticationServiceException("login fail");
 | 
			
		||||
        }
 | 
			
		||||
         */
 | 
			
		||||
        return authenticationManager.authenticate(authToken);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -69,23 +53,22 @@ public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter
 | 
			
		||||
                                            FilterChain chain, Authentication authResult) throws IOException, ServletException {
 | 
			
		||||
 | 
			
		||||
        UserDetails userDetails = (UserDetails) authResult.getPrincipal();
 | 
			
		||||
 | 
			
		||||
        MemberDto member = (MemberDto) userDetails;
 | 
			
		||||
        
 | 
			
		||||
        String accessToken = jwtUtils.generateToken(member.getUserId(), member.getRole().getValue(),
 | 
			
		||||
                Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_access"))));
 | 
			
		||||
 | 
			
		||||
        // 모듈화된 메서드 사용
 | 
			
		||||
        String refreshToken = jwtUtils.createAndSaveRefreshToken(member.getUserId(), member.getRole().getValue());
 | 
			
		||||
        // 토큰 생성
 | 
			
		||||
        String accessToken = jwtUtils.createAccessToken(member.getUserId(), member.getRole().getValue());
 | 
			
		||||
        String refreshToken = jwtUtils.createRefreshToken(member.getUserId(), member.getRole().getValue());
 | 
			
		||||
        
 | 
			
		||||
        // Refresh 토큰을 DB에 저장
 | 
			
		||||
        jwtUtils.saveRefreshToken(member.getUserId(), refreshToken);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        member.setRefreshToken(refreshToken);
 | 
			
		||||
        member.setLastLoginAt(LocalDateTime.now());
 | 
			
		||||
 | 
			
		||||
        // Refresh 토큰 쿠키 저장 - 모듈화된 메서드 사용
 | 
			
		||||
        // Refresh 토큰 쿠키 저장
 | 
			
		||||
        jwtUtils.setRefreshTokenCookie(response, refreshToken);
 | 
			
		||||
 | 
			
		||||
        // JWT 토큰 전달
 | 
			
		||||
        // Access 토큰 전달
 | 
			
		||||
        response.setHeader("Authorization", "Bearer " + accessToken);
 | 
			
		||||
 | 
			
		||||
        SecurityContextHolderStrategy contextHolder = SecurityContextHolder.getContextHolderStrategy();
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
package com.bio.bio_backend.global.security;
 | 
			
		||||
package com.bio.bio_backend.global.filter;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
@@ -21,6 +21,7 @@ import com.bio.bio_backend.global.dto.ApiResponseDto;
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
 | 
			
		||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
 | 
			
		||||
import com.bio.bio_backend.global.utils.JwtUtils;
 | 
			
		||||
import com.bio.bio_backend.global.config.SecurityPathConfig;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
 | 
			
		||||
@@ -31,16 +32,14 @@ public class JwtTokenValidationFilter extends OncePerRequestFilter {
 | 
			
		||||
    private final JwtUtils jwtUtils;
 | 
			
		||||
    private final MemberService memberService;
 | 
			
		||||
    private final Environment env;
 | 
			
		||||
    private final SecurityPathConfig securityPathConfig;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
 | 
			
		||||
        String path = request.getRequestURI();
 | 
			
		||||
        // permitAll 경로는 JWT 검증을 건너뜀 (WebSecurity.java의 설정과 동기화)
 | 
			
		||||
        return path.equals("/login") ||
 | 
			
		||||
               path.startsWith("/members/register") ||
 | 
			
		||||
               path.startsWith("/swagger-ui/") ||
 | 
			
		||||
               path.startsWith("/api-docs/") ||
 | 
			
		||||
               path.startsWith("/ws/");
 | 
			
		||||
        String contextPath = env.getProperty("server.servlet.context-path", "");
 | 
			
		||||
        
 | 
			
		||||
        return securityPathConfig.isPermittedPath(path, contextPath);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -1,11 +1,9 @@
 | 
			
		||||
package com.bio.bio_backend.global.security;
 | 
			
		||||
package com.bio.bio_backend.global.filter;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.regex.Pattern;
 | 
			
		||||
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletRequest;
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package com.bio.bio_backend.global.security;
 | 
			
		||||
 | 
			
		||||
import com.bio.bio_backend.global.filter.JwtTokenIssuanceFilter;
 | 
			
		||||
import com.bio.bio_backend.global.filter.JwtTokenValidationFilter;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.core.env.Environment;
 | 
			
		||||
@@ -18,9 +20,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 | 
			
		||||
 | 
			
		||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
 | 
			
		||||
import com.bio.bio_backend.global.exception.CustomAuthenticationFailureHandler;
 | 
			
		||||
import com.bio.bio_backend.global.exception.JwtAccessDeniedHandler;
 | 
			
		||||
import com.bio.bio_backend.global.exception.JwtAuthenticationEntryPoint;
 | 
			
		||||
import com.bio.bio_backend.global.utils.JwtUtils;
 | 
			
		||||
import com.bio.bio_backend.global.config.SecurityPathConfig;
 | 
			
		||||
import lombok.RequiredArgsConstructor;
 | 
			
		||||
 | 
			
		||||
@Configuration
 | 
			
		||||
@@ -33,18 +34,17 @@ public class WebSecurity {
 | 
			
		||||
    private final JwtUtils jwtUtils;
 | 
			
		||||
    private final ObjectMapper objectMapper;
 | 
			
		||||
    private final Environment env;
 | 
			
		||||
    private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
 | 
			
		||||
    private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
 | 
			
		||||
    private final SecurityPathConfig securityPathConfig;
 | 
			
		||||
 | 
			
		||||
    private JwtTokenIssuanceFilter getJwtTokenIssuanceFilter(AuthenticationManager authenticationManager) throws Exception {
 | 
			
		||||
        JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, memberService, jwtUtils, env, objectMapper);
 | 
			
		||||
        filter.setFilterProcessesUrl("/login"); // 로그인 EndPoint
 | 
			
		||||
        JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper);
 | 
			
		||||
        filter.setFilterProcessesUrl("/login");
 | 
			
		||||
        filter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler(objectMapper));
 | 
			
		||||
        return filter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private JwtTokenValidationFilter getJwtTokenValidationFilter() {
 | 
			
		||||
        return new JwtTokenValidationFilter(jwtUtils, memberService, env);
 | 
			
		||||
        return new JwtTokenValidationFilter(jwtUtils, memberService, env, securityPathConfig);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -59,12 +59,13 @@ public class WebSecurity {
 | 
			
		||||
 | 
			
		||||
        AuthenticationManager authenticationManager = authenticationManagerBuilder.build();
 | 
			
		||||
 | 
			
		||||
        // 설정 파일에서 허용할 경로 가져오기
 | 
			
		||||
        String[] permitAllPaths = securityPathConfig.getPermitAllPaths().toArray(new String[0]);
 | 
			
		||||
 | 
			
		||||
        http.csrf(AbstractHttpConfigurer::disable)          //csrf 비활성화
 | 
			
		||||
                .authorizeHttpRequests(request ->               //request 허용 설정
 | 
			
		||||
                        request
 | 
			
		||||
                            .requestMatchers("/members/register").permitAll()
 | 
			
		||||
                            .requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll()  // Swagger 허용
 | 
			
		||||
                            .requestMatchers("/ws/**").permitAll()  // WebSocket 허용
 | 
			
		||||
                            .requestMatchers(permitAllPaths).permitAll()  // 설정 파일에서 허용할 경로
 | 
			
		||||
                            .anyRequest().authenticated()  // 나머지 요청은 인증 필요
 | 
			
		||||
                )
 | 
			
		||||
                .authenticationManager(authenticationManager)
 | 
			
		||||
@@ -72,14 +73,6 @@ public class WebSecurity {
 | 
			
		||||
                    session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)  // 세션 사용 안함
 | 
			
		||||
                )
 | 
			
		||||
                .logout(AbstractHttpConfigurer::disable);
 | 
			
		||||
 | 
			
		||||
        // 예외 처리 핸들링
 | 
			
		||||
        http.exceptionHandling((exceptionConfig) ->
 | 
			
		||||
                exceptionConfig
 | 
			
		||||
                        .authenticationEntryPoint(jwtAuthenticationEntryPoint)
 | 
			
		||||
                        .accessDeniedHandler(jwtAccessDeniedHandler)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        http
 | 
			
		||||
            // 1단계: JWT 토큰 발급 필터 (로그인 요청 처리 및 토큰 발급)
 | 
			
		||||
            .addFilterBefore(getJwtTokenIssuanceFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class)
 | 
			
		||||
 
 | 
			
		||||
@@ -93,17 +93,30 @@ public class JwtUtils {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Refresh Token 생성 및 DB 저장
 | 
			
		||||
    public String createAndSaveRefreshToken(String username, String role) {
 | 
			
		||||
        String refreshToken = generateToken(username, role,
 | 
			
		||||
    // Access Token 생성
 | 
			
		||||
    public String createAccessToken(String username, String role) {
 | 
			
		||||
        return generateToken(username, role,
 | 
			
		||||
                Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_access"))));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Refresh Token 생성
 | 
			
		||||
    public String createRefreshToken(String username, String role) {
 | 
			
		||||
        return generateToken(username, role,
 | 
			
		||||
                Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh"))));
 | 
			
		||||
        
 | 
			
		||||
        // MemberDto 객체 생성하여 updateRefreshToken 호출
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Refresh Token을 DB에 저장
 | 
			
		||||
    public void saveRefreshToken(String username, String refreshToken) {
 | 
			
		||||
        MemberDto member = new MemberDto();
 | 
			
		||||
        member.setUserId(username);
 | 
			
		||||
        member.setRefreshToken(refreshToken);
 | 
			
		||||
        memberService.updateRefreshToken(member);
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Refresh Token 생성 및 DB 저장 (기존 호환성을 위한 메서드)
 | 
			
		||||
    public String createAndSaveRefreshToken(String username, String role) {
 | 
			
		||||
        String refreshToken = createRefreshToken(username, role);
 | 
			
		||||
        saveRefreshToken(username, refreshToken);
 | 
			
		||||
        return refreshToken;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 
 | 
			
		||||
@@ -94,4 +94,9 @@ springdoc.swagger-ui.tagsSorter=alpha
 | 
			
		||||
springdoc.swagger-ui.doc-expansion=none
 | 
			
		||||
springdoc.swagger-ui.disable-swagger-default-url=true
 | 
			
		||||
springdoc.default-produces-media-type=application/json
 | 
			
		||||
springdoc.default-consumes-media-type=application/json
 | 
			
		||||
springdoc.default-consumes-media-type=application/json
 | 
			
		||||
 | 
			
		||||
# ========================================
 | 
			
		||||
# 보안 설정 - 허용할 경로
 | 
			
		||||
# ========================================
 | 
			
		||||
security.permit-all-paths=/login,/members/register,/swagger-ui/**,/api-docs/**,/ws/**
 | 
			
		||||
		Reference in New Issue
	
	Block a user