Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,23 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.postgresql:postgresql:42.7.3'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// postgreSql
runtimeOnly 'org.postgresql:postgresql'
implementation 'org.postgresql:postgresql:42.7.3'

// jwt
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

// swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
}

tasks.named('test') {
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/run/backend/global/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package run.backend.global.config;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;


@Configuration
@OpenAPIDefinition(
info = @Info(
title = "Runners-Fight API",
description = "Runners-Fight 서비스의 API 명세서입니다.",
version = "v1"
)
)
public class SwaggerConfig {

@Value("${swagger.server.url.prod}")
private String prodUrl;

@Bean
public OpenAPI openAPI() {
String jwt = "JWT";
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwt);
Components components = new Components().addSecuritySchemes(jwt, new SecurityScheme()
.name(jwt)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("jwt")
);

return new OpenAPI()
.addSecurityItem(securityRequirement)
.components(components)
.servers(List.of(
new Server().url("http://localhost:8080").description("local server"),
new Server().url(prodUrl).description("production server")
));
}
}
81 changes: 70 additions & 11 deletions src/main/java/run/backend/global/security/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
Expand All @@ -22,24 +31,74 @@
@RequiredArgsConstructor
public class SecurityConfig {

@Value("${swagger.id}")
private String swaggerUser;

@Value("${swagger.pwd}")
private String swaggerPassword;

private final JwtTokenProvider jwtTokenProvider;

private final String[] SwaggerPatterns = {
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/swagger"
};

private final String[] PermitAllPatterns = {
"/api/v1/auth/**"
};

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable).httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable);
public UserDetailsService userDetailsService() {
UserDetails user =
User.withUsername(swaggerUser)
.password(passwordEncoder().encode(swaggerPassword))
.roles("SWAGGER")
.build();
return new InMemoryUserDetailsManager(user);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런건 어떻게 아셨어요..? 시큐리티 고수,,,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋ api 외부로 노출되면 안 된다고 해서..

}

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

@Bean
@Order(1)
public SecurityFilterChain swaggerSecurityFilterChain(HttpSecurity http) throws Exception {
http
.securityMatcher(SwaggerPatterns)
.authorizeHttpRequests(authorize -> authorize
.anyRequest().hasRole("SWAGGER")
)
.httpBasic(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable);

return http.build();
}

http.sessionManagement(
session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
@Bean
@Order(2)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.securityMatcher(PermitAllPatterns)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기에 permitAllPatterns가 들어가면 저기에만 시큐리티 적용 아닌가요??

Copy link
Contributor Author

@choiseoji choiseoji Jul 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

securityMatcher에 있는 uri에 대해서 해당 필터 체인을 적용하겠다는 의미로 적었습니다!!!
(저거 추가 안하니깐 스웨거 요청도 다 저 필터 체인으로 걸리길래..추가했습니다)

.csrf(AbstractHttpConfigurer::disable)
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable);

http.authorizeHttpRequests(
authorize -> authorize.requestMatchers("/api/v1/auth/**").permitAll().anyRequest()
.authenticated());
http
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.cors(cors -> cors.configurationSource(corsConfigurationSource()));

http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(PermitAllPatterns).permitAll()
.anyRequest().authenticated());

http.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class);
http
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);

return http.build();
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,19 @@ jwt:

file:
upload:
dir: ${user.home}/${UPLOAD_DIR}
dir: ${user.home}/${UPLOAD_DIR}

swagger:
id: ${SWAGGER_ID}
pwd: ${SWAGGER_PWD}
server:
url:
prod: ${SERVER_URI}

springdoc:
api-docs:
enabled: true
swagger-ui:
enabled: true
path: /swagger
override-with-generic-response: false