Skip to content

maeveWoo/spring-boot-labs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

42 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

spring-boot-labs

Index




SpringBoot๊ธฐ์ดˆ

@SpringBootApplication์€ ์•„๋ž˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ํฌํ•จํ•˜๊ณ ๋Š” ํŽธ๋ฆฌํ•œ ์–ด๋…ธํ…Œ์ด์…˜์ด๋‹ค.

  • @Configuration : application context์—๋Œ€ํ•œ ๋นˆ ์ •์˜์˜ ์†Œ์Šค๋กœ, ํด๋ž˜์Šค์— ํƒœ๊ทธ๋ฅผ ํ•œ๋‹ค.
  • @EnableAutoConfiguration : ํด๋ž˜์Šค ํŒจ์Šค ์„ธํŒ…, ๋‹ค๋ฅธ ๋นˆ๋“ค๊ณผ ๋‹ค์–‘ํ•œ ํ”„๋กœํผํ‹ฐ ์„ธํŒ…์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋นˆ์„ ๋“ฑ๋กํ•˜๊ฒŒ ํ•œ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด spring-webmvc ๊ฐ€ ํด๋ž˜์ŠคํŒจ์Šค์— ์žˆ์œผ๋ฉด, ์ด ์–ด๋…ธํ…Œ์ด์…˜์€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ํ”Œ๋ž˜๊ทธํ•˜๊ณ , DispatcherServlet์„ธํŒ…์„๊ณผ ๊ฐ™์€ ํ•ต์‹ฌ ๋™์ž‘์„ ํ™œ์„ฑํ™”ํ•œ๋‹ค.

  • @ComponentScan : ์Šคํ”„๋ง์ด ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค๊ณผ, ์„ค์ •๋“ค๊ณผ ์„œ๋น„์Šค๋“ค์„ ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์ฐพ๋„๋ก ํ•œ๋‹ค.

Run the Application

gradle ๊ธฐ๋ฐ˜

./gradlew bootRun

maven

./mvnw spring-boot:run

Add Unit Tests

MockMvc๋Š” Spring Test์—์„œ ์™”๋‹ค. ์ด๊ฒƒ์€ ํŽธ๋ฆฌํ•œ ๋นŒ๋” ํด๋ž˜์Šค๋“ค๊ณผ HTTP request๋“ค์„ DispatcherServlet์— ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ assertions์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

MockMvc๋ฅผ ์ฃผ์ž…ํ•˜๊ธฐ์œ„ํ•ด ์‚ฌ์šฉ๋œ @AutoConfigureMockMvc์™€ @SpringBootTest ์‚ฌ์šฉ์„ ๊ธฐ๋กํ•˜์ž.

@SpringBootTest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์ „์ฒด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๋„๋ก ์š”์ฒญํ•œ๋‹ค.

๋Œ€์•ˆ์œผ๋กœ @WebMvcTest๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปจํ…์ŠคํŠธ์˜ ์›น ๊ณ„์ธต๋งŒ ์ƒ์„ฑํ•˜๋„๋ก ์Šคํ”„๋ง๋ถ€ํŠธ์— ์š”์ฒญํ•œ๋‹ค.

์ด ๋‘๊ฐ€์ง€ ๊ฒฝ์šฐ ๋ชจ๋‘, ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์ž๋™์œผ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํด๋ž˜์Šค๋กœ ์œ„์น˜ํ•˜๋ ค ์‹œ๋„ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๊ฐœ๋ฐœ์ž๋Š” ๋ฎ์–ด์“ฐ๊ฑฐ๋‚˜, ์•ฝ๊ฐ„์˜ ๋‹ค๋ฅธ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

๋ฟ๋งŒ์•„๋‹ˆ๋ผ, ์Šคํ”„๋ง๋ถ€ํˆฌ๋ฅผ ์‚ฌ์šฉํ•ด ํ’€์Šคํƒ ํ†ตํ•ฉํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ, HTTP Request cycle์„ ๋ชจํ‚นํ•œ๋‹ค.

์ฐธ๊ณ 

๋‚ด์žฅ์„œ๋ฒ„๋Š” webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT๋•Œ๋ฌธ์— ๋žœ๋ค ํฌํŠธ๋กœ ์‹œ์ž‘๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ ํฌํŠธ๋Š” ์ž๋™์œผ๋กœ TestRestTemplate๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธURL์— ์„ค์ •๋œ๋‹ค.

Add Production-grade Services

์Šค๋ถ€๋Š” health, audits, beans,..๋“ฑ์˜ ์„œ๋น„์Šค๋Š” actuator module๊ณผ ํ•จ๊ป˜ ์ œ๊ณตํ•œ๋‹ค.

implementation 'org.springframework.boot:spring-boot-starter-actuator'

์ด ์œ„์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ  bootRun์„ ์‹คํ–‰ํ•˜๋ฉด, ์ƒˆ๋กœ์šด RESTful ์—”๋“œํฌ์ธํŠธ๋“ค์ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ถ”๊ฐ€๋œ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

management.endpoint.configprops-org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointProperties
management.endpoint.env-org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointProperties
management.endpoint.health-org.springframework.boot.actuate.autoconfigure.health.HealthEndpointProperties
management.endpoint.logfile-org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointProperties
management.endpoints.jmx-org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointProperties
management.endpoints.web-org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties
management.endpoints.web.cors-org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties
management.health.diskspace-org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthIndicatorProperties
management.info-org.springframework.boot.actuate.autoconfigure.info.InfoContributorProperties
management.metrics-org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties
management.metrics.export.simple-org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleProperties
management.server-org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties

actuator๋Š” ๋‹ค์Œ์„ ๋…ธ์ถœํ•œ๋‹ค.

  • actuator/health
  • actuator

/actuator/shutdown ์—”๋“œํฌ์ธํŠธ๋„ ์žˆ๋‹ค, ํ•˜์ง€๋งŒ ์ด๋Š” JMX1๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ HTTP ์—”ํŠธํฌ์ธํŠธ๋กœ ๋งŒ๋“ค๊ธฐ์œ„ํ•ด management.endpoint.shutdown.enable=true ๋ฅผ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœํผํ‹ฐ์— ์ถ”๊ฐ€ํ•˜์ž. ๊ทธ๋ฆฌ๊ณ  management.endpoints.web.exposure.include=health,info,shutdown ์š”๊ฒƒ๋„ ๋…ธ์ถœ์‹œํ‚ค์ž. ๊ทธ๋Ÿฌ๋‚˜, ๋„ˆ๋Š” ๊ณต๊ฐœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ shutdown ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋ฉด ์•ˆ๋  ์ˆ˜๋„ ์žˆ๋‹ค.

์•ˆ๋Œ€๋Š”๋ฐ?

JAR ์ง€์› ๋ฐ Groovy ์ง€์›

SpringBoot Loader Module2 ๋•๋ถ„์— ๊ธฐ์กด์˜ WAR ํŒŒ์ผ ๋ฐฐํฌ๋ฅผ ์ง€์›ํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ JAR๋ฅผ ํ•จ๊ป˜ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค.

spring-boot-gradle-plugin, spring-boot-maeven-plugin์„ ํ†ตํ•ด ์ด๋‘˜์„ ๋ฐ๋ชจ๋ฅผ ์ง€์›ํ•˜๋Š” ๋‹ค์–‘ํ•œ ๊ฐ€์ด๋“œ๊ฐ€์žˆ๋‹ค.

ํ•˜๋‚˜์˜ ํŒŒ์ผ๋งŒํผ ์ž‘์€ Spring MVC web ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๊ฒŒ, ์Šค๋ถ€๋Š” Groovy๋„ ์ง€์›ํ•œ๋‹ค.

(์™€์”จ ๋Œ€๋ฐ•!!)

root ๊ฒฝ๋กœ์— app.groovy๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค์Œ์ฝ”๋“œ๋ฅผ ๋„ฃ๋Š”๋‹ค.

@RestController
class ThisWillActuallyRun {

    @GetMapping("/")
    String home() {
        return "Hello, World!"
    }

}

๋จผ์ € Springboot CLI๋ฅผ ์„ค์น˜(mac์šฉ)

์•„๋ž˜ ์ปค๋ฉ˜๋“œ ์‹คํ–‰

$ spring run app.groovy

์Šค๋ถ€๋Š” ๋™์ ์œผ๋กœ ํ•ต์‹ฌ ์• ๋…ธํ…Œ์ด์…˜๋“ค๊ณผ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด์„œ ์‹คํ–‰ํ•œ๋‹ค.

GroovyGrape3๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์•ฑ์„ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ฐ›๋Š”๋‹ค.

Spring Security Architecture

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์ธ์€ ์ธ์ฆ(Authentication : ๋‹น์‹ ์€ ๋ˆ„๊ตฌ?)๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ(์ธ๊ฐ€)(Authorization : ๋‹น์‹ ์€ ๋ญ˜ ํ•  ์ˆ˜ ์žˆ์Œ?)๋ผ๋Š” ๋‘ ๊ฐ€์ง€ ๋…๋ฆฝ์ ์ธ ๋ฌธ์ œ๋กœ ์š”์•ฝ๋œ๋‹ค.

๋•Œ๋•Œ๋กœ ์‚ฌ๋žŒ๋“ค์€ "๊ถŒํ•œ ๋ถ€์—ฌ(์ธ๊ฐ€)"๋Œ€์‹  "์ ‘๊ทผ ๊ด€๋ฆฌ"๋ผ๊ณ ๋„ ํ•œ๋‹ค.

Spring Security๋Š” ์ธ์ฆ๊ณผ ์ธ๊ฐ€๋ฅผ ๋ถ„๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„๋™จ ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์ด๋‘˜์— ์ „๋žต๊ณผ ํ™•์žฅ ํฌ์ธํŠธ๋ฅผ ๊ฐ–๊ฒŒํ•œ๋‹ค.

์ธ์ฆ(Authentication)

์ธ์ฆ์„ ์œ„ํ•œ ์ฃผ ์ „๋žต ์ธํ„ฐํŽ˜์ด์Šค๋Š” AuthenticationManager์ด๋‹ค. AuthenticationManager๋Š” ํ•˜๋‚˜์˜ ๋ฉ”์†Œ๋“œ๋งŒ ๊ฐ€์ง„๋‹ค.

public interface AuthenticationManager {
  Authentication authenticate(Authentication authentication)
          throws AuthenticationException;
}

AuthenticationManager์€ authenticate() ๋ฉ”์†Œ๋“œ๋กœ 3๊ฐ€์ง€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ž…๋ ฅํ•œ ๊ฐ’์ด ์œ ํšจํ•œ ์›์น™(principal)์ธ์ง€ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, Authentication(์ผ๋ฐ˜์ ์œผ๋กœ authenticated=true์™€ ํ•จ๊ป˜)์„ ๋ฐ˜ํ™˜
  • ์ž…๋ ฅํ•œ ๊ฐ’์ด ์œ ํšจํ•˜์ง€ ์•Š์€ ์›์น™์ž„์„ ํ™•์ธํ•œ๋‹ค๋ฉด, AuthenticationException์„ ๋˜์ง„๋‹ค.
  • ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†์„ ๊ฒฝ์šฐ null์„ ๋ฐ˜

AuthenticationException์€ Runtime Exception์ด๋‹ค.

AuthenticationException์€ ๋ณดํ†ต ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์Šคํƒ€์ผ์ด๋‚˜, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชฉ์ ์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌ๋œ๋‹ค.

์ฆ‰, ์‚ฌ์šฉ์ž์˜ ์ฝ”๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ด ์ต์…‰์…˜์„ ์žก๊ฑฐ๋‚˜ ํ•ธ๋“ค๋งํ•˜๊ธฐ๋ฅผ ๋ฐ”๋ผ์ง€ ์•Š๋Š”๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด, ์›น UI๋Š” ์ธ์ฆ์ด ์‹คํŒจํ–ˆ๋‹ค๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๊ณ , WWW-Authenticateheader๊ฐ€ ๊ฐ™์ด(๊ฐ™์ด ์•ˆ์˜ฌ ์Šˆ๋„ ์žˆ์Œ), backend HTTP๋Š” 401 ์‘๋‹ต์„ ์ค„๊ฒƒ์ด๋‹ค.

๋” ์ผ๋ฐ˜์ ์ธ AuthenticationManager์˜ ๊ตฌํ˜„์€ ProviderManager์ด๋‹ค.

ProviderManager์€ AuthenticationProviderํ•œ ์ธ์Šคํ„ด์Šค ์ฒด์ธ์—๊ฒŒ ์œ„์ž„์„ ํ•œ๋‹ค.

AuthenticationProvider๋Š” AuthenticationManager๊ณผ ์•ฝ๊ฐ„ ๋น„์Šทํ•˜์ง€๋งŒ, ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ–๋Š”๋‹ค.

์ด ๋ฉ”์„œ๋“œ๋Š” AuthenticationProvider์ด ์ฃผ์–ด์ง„ ์ธ์ฆํƒ€์ž…์„ ์ง€์›ํ•˜๋Š”์ง€ ํ˜ธ์ถœ์ž์—๊ฒŒ ๋ฌผ์„ ์ˆ˜ ์žˆ๊ฒŒ ํ—ˆ๋ฝํ•œ๋‹ค.

public interface AuthenticationProvider {

  Authentication authenticate(Authentication authentication)
          throws AuthenticationException;

  boolean supports(Class<?> authentication);
}

์ด supports()๋ฉ”์†Œ๋“œ์˜ Class<?> ์ธ์ž๋Š” ์‹ค์ œ๋กœClass<? extends Authentication>์ด๋‹ค. (์ด ์ธ์ž๋Š” authenticate() ๋ฉ”์†Œ๋“œ๋ฅผ ์ง€์›ํ•˜๋Š”์ง€๋งŒ ๋ฌผ์–ด๋ณธ๋‹ค.)

ProviderManager๋Š” AuthenticationProviders์˜ ์ฒด์ธ์—๊ฒŒ ๊ฐ™์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์œ„์ž„์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋‹ค๋ฅธ ์ธ์ฆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ProviderManager๊ฐ€ ์ธ์ฆ ์ธ์Šคํ„ด์Šค์˜ ํƒ€์ž… ์ผ๋ถ€๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•˜๋ฉด, ์ด๋Š” ๋„˜์–ด๊ฐ„๋‹ค.(skip)

ProviderManager ์„ ํƒ์ ์œผ๋กœ ๋ถ€๋ชจ๋ฅผ ๊ฐ™์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ. ์ด๋Š” ๋งŒ์•ฝ ๋ชจ๋“  ์ œ๊ณต์ž๊ฐ€ null์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋ฉด ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๋ญ”์†Œ๋ฆฌ์•ผ ์ œ๊ณต์ž๊ฐ€ ์ „๋ถ€ null์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ถ€๋ชจ๋ฅผ ๊ฐ–๋Š”๊ฒŒ ์ข‹๋‹ค๋Š” ๋œป์ธ๋“ฏ)

๋งŒ์•ฝ ๋ถ€๋ชจ๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๋‹ค๋ฉด, null ์ธ์ฆ ๊ฒฐ๊ณผ๋Š” AuthenticationException์ด๋‹ค.

๋•Œ๋•Œ๋กœ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์˜ ๋…ผ๋ฆฌ์  ๊ทธ๋ฃน์„ ๊ฐ–๋Š”๋‹ค.(ex: path pattern ๋งค์นญ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ์›น ์ž์›)

๊ทธ๋ฆฌ๊ณ  ๊ฐ ๊ทธ๋ฃน์€ ๊ทธ๋“ค์˜ ๊ณ ์œ ํ•œ AuthenticationManager๋ฅผ ๊ฐ–๋Š”๋‹ค.

์ž์ฃผ, ๊ฐ๊ฐ์˜ AuthenticationManager๋Š” ProviderManager์ด๊ณ , ์ด๋“ค์€ ๋ถ€๋ชจ๋ฅผ ๊ณต์œ ํ•œ๋‹ค.

์ด ๋ถ€๋ชจ๋Š” "global"์ž์›์˜ ํ•œ ์ข…๋ฅ˜๋กœ, ๋ชจ๋“  ์ œ๊ณต์ž์—๊ฒŒ ์˜ˆ๋น„ํ’ˆ(fallback)์ฒ˜๋Ÿผ ๋™์ž‘ํ•œ๋‹ค.

Customizing Authentication Managers

์Šคํ”„๋ง ์‹œํ๋Ÿฌํ‹ฐ๋Š” ์‚ฌ์šฉ์ž ์–ดํ”Œ๋ฆฌ์ผ€์ด์„ ์— ๋น ๋ฅด๊ฒŒ ์ผ๋ฐ˜์ ์ธ ์ธ์ฆ ๋งค๋‹ˆ์ €์˜ ํŠน์ง•์„ ์…‹์—…ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช‡๋ช‡ ์„ค์ •์„ ์ œ๊ณตํ•œ๋‹ค.

๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ—ฌํผ๋Š” AuthenticationManagerBuilder์ด๋‹ค.

AuthenticationManagerBuilder๋Š” ์ธ๋ฉ”๋ชจ๋ฆฌ, JDBC, LDAP ์‚ฌ์šฉ์ž ์„ธ๋ถ€์‚ฌํ•ญ ๋˜๋Š” ์ปค์Šคํ…€ํ•œUserDetailService์ถ”๊ฐ€ ์…‹์—…์— ํ›Œ๋ฅญํ•˜๋‹ค.

๋‹ค์Œ ์˜ˆ์ œ๋Š” global(parent) AuthenticationManager์„ค์ •์„ํ•œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ณด์—ฌ์ค€๋‹ค.

import javax.sql.DataSource;

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
  ... // web stuff  here

  @Autowired
  public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
      builder.jdbcAuthentication().dataSource(dataSource).withUser("dave").password("secret").roles("USER");
  }
}

์ด ์˜ˆ์ œ๋Š” ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๊ด€๋ จ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, AuthenticationManagerBuilder๋Š” ๋” ๋„“๊ฒŒ ์“ฐ์ผ ์ˆ˜ ์žˆ๋‹ค.(web security4)

์ดAuthenticationManagerBuilder๋Š” @Autowired์ด๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š”@Bean์œผ๋กœ ๋“ฑ๋ก๋ฌ๋‹ค.

์ด๋Š” AuthenticationManager๋ฅผ global(parent)๋ฅผ ์ œ๊ณตํ•˜๊ฒŒํ•œ๋‹ค.

๋Œ€์กฐ์ ์œผ๋กœ ์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์ž

import javax.sql.DataSource;

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

  @Autowired
  DataSource dataSource;
  
  ... // web stuff here 
  
  @Override
  public void configure(AuthenticationManagerBuilder builder) {
      builder.jdbcAuthentication().dataSource(dataSource).withUser("dave").password("secret").roles("USER");
  }
}

โš ๏ธ In Spring-security 5.7 M2 deprecated WebSecurityConfigurerAdapter ์‚ฌ์šฉ์ž๊ฐ€ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜์˜ security ์„ค์ •์„ ํ•˜๋„๋ก ๊ถŒ์žฅํ•˜๊ณ ์žˆ๋‹ค. docs : https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter

๋งŒ์•ฝ ์„ค์ •์—์„œ ๋ฉ”์†Œ๋“œ์— @Override๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด, AuthenticationManagerBuilder๋Š” global์˜ child๊ฐ€ ๋  "local"AuthenticationManager๋ฅผ ๊ตฌ์„ฑํ•  ๋ฟ์ด๋‹ค.

์Šค๋ถ€์—์„œ๋Š” global AuthenticationManagerBuilder๋ฅผ ๋‹ค๋ฅธ ๋นˆ์— ์ฃผ์ž…@Autowiredํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜, local์ธ ๊ฒƒ์„ ๋ช…์‹œ์ ์œผ๋กœ ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š” ํ•œ, @Autowired๋กœ ์ฃผ์ž…ํ•  ์ˆ˜ ์—†๋‹ค.

์Šค๋ถ€๋Š” default global AuthenticationManager๋ฅผ ์ œ๊ณตํ•œ๋‹ค. (์‚ฌ์šฉ์ž๊ฐ€ AuthenticationManagerํƒ€์ž…์˜ ๋นˆ์„ ์„ ์ ํ•ด์„œ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ํ•œ)

์ด ๊ธฐ๋ณธ๊ฐ’์€ ์ถฉ๋ถ„ํžˆ ์•ˆ์ „ํ•˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์ •์˜ global์ด ์ ๊ทน์ ์œผ๋กœ ํ•„์š”ํ•˜์ง€ ์•Š๋Š” ํ•œ ํฌ๊ฒŒ ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๋งŒ์•ฝ AuthenticationManager ๋นŒ๋“œ๋ฅผ ์œ„ํ•ด ์–ด๋–ค ์„ค์ •์„ ํ•˜๋ คํ•œ๋‹ค๋ฉด, global ๊ธฐ๋ณธ๊ฐ’์—๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜์ง€์•Š๊ณ , ์ฃผ๋กœ ์‚ฌ์šฉ์ž๋Š” ๋ณดํ˜ธํ•˜๋ ค๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ์œ„ํ•ด locallyํ•˜๊ฒŒ ๋งŒ๋“ค๋ฉด๋œ๋‹ค.

Authorizatiob or Access Control

authorization์˜ ํ•ต์‹ฌ ์ „๋žต์€ "AccessDecisionManager"์ด๋‹ค.

ํ”„๋ ˆ์ž„์›Œํฌ๋Š” 3๊ฐ€์ง€ ๊ตฌํ˜„์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์„ธ๊ฐ€์ง€๋Š” "AccessDecisionVoter"์˜ ์ฒด์ธ ์ธ์Šคํ„ด์Šค์— ์œ„์ž„ํ•œ๋‹ค.

"ProviderManager"๊ฐ€ "AuthenticationProviders"์— ์œ„์ž„ํ•˜๋Š” ๊ฒƒ๊ณผ์•ฝ๊ฐ„ ๋น„์Šทํ•˜๋‹ค.

"AccessDecisionVoter"๋Š” "Authentication"์„ ๊ณ ๋ คํ•˜๊ณ (์›์น™(principal ์„ ํ‘œํ˜„)), "ConfigAttributes"๋กœ ๋ฐ์ฝ”๋ ˆํŠธ๋œ "Object"๋ฅผ ๋ณดํ˜ธํ•œ๋‹ค.

boolean supports(ConfigAttribute attribute);

boolean supports(Class<?> clazz);

int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);

"AccessDecisionManager", "AccessDecisionVoter"์˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜์—์„œ "Object"๋Š” ์™„์ „ํžˆ ์ œ๋„ค๋ฆญ์ด๋‹ค.

์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผ(์›น ๋ฆฌ์†Œ์Šค๋‚˜, ์ž๋ฐ” ๋ฉ”์„œ๋“œ ๋‘๊ฐœ๋Š” ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ์ผ€์ด์Šค)์„ ์›ํ•˜๋Š” ์–ด๋– ํ•œ ๊ฒƒ๋„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

"ConfigAttributes"์—ญ์‹œ ์ œ๋„ค๋ฆญ์ด๋‹ค. ๋˜, ๊ทธ๊ฒƒ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ถŒํ•œ๋ ˆ๋ฒจ์„ ๊ฒฐ์ •ํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ "Object"์˜ ๋ณด์•ˆ ๋ฐ์ฝ”๋ ˆ์ด์…˜์„ ๋ณด์—ฌ์ค€๋‹ค.

"ConfigAttribute" ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. ์–˜๋Š” ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋งŒ ๊ฐ–๋Š”๋‹ค(์ด ๋ฉ”์„œ๋“œ๋Š” ์ œ๋„ค๋ฆญ์ด๊ณ  "String"์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.) ๊ทธ๋ž˜์„œ ์ด ๋ฌธ์ž์—ด์€ ์ž์›์˜ ์†Œ์œ ์ž์˜ ์˜๋„๋Œ€๋กœ ์•”ํ˜ธํ™”(encode)๋œ๋‹ค.

์ด๋Š” ๋ˆ„๊ฐ€ ๊ทธ๊ฒƒ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ทœ์น™์„ ํ‘œํ˜„ํ•œ๋‹ค.

์œ ํ˜•๋ณ„ "ConfigAttribute"๋Š” ์‚ฌ์šฉ์ž ์—ญํ• ์˜ ์ด๋ฆ„์ด๋ฉฐ("ROLE_ADMIN", "ROLE_AUDOT"๊ฐ™์€) ๊ทธ๋ฆฌ๊ณ , ์•ผ๋“ค์€ ํŠน๋ณ„ํ•œ ํฌ๋งท("ROLE_"๊ฐ™์€)์ด ์žˆ๊ฑฐ๋‚˜ ํ‰๊ฐ€๊ฐ€ ํ•„์š”ํ•œ ํ‘œํ˜„์„ ๋ณด์—ฌ์ค€๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ "ConfigAttributes"sms Spring Expression Language(SpEL)ํ‘œํ˜„์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, "isFullyAuthenticated() && hasRole('user')" ์ด ํ‘œํ˜„์€ "AccessDecisionVoter"๊ฐ€ ์ง€์›ํ•ด์ค€๋‹ค.

"AccessDecisionVoter"๋Š” ํ‘œํ˜„์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ณ , ๊ทธ๋“ค์„ ์œ„ํ•ด ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

ํ‘œํ˜„๋ฒ•์˜ ๋ฒ”์œ„๋ฅผ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•ด "SecurityExpressionRoot"๊ณผ ๊ฐ€๋” "SecurityExpressionHandler"์˜ ์ปค์Šคํ…€ ๊ตฌํ˜„์ฒด๋ฅผ ํ•„์š”๋กœํ•œ๋‹ค.

Web Security

์›น ๊ณ„์ธต์—์„œ Spring Security๋Š” Servlet "Filters"์— ๊ธฐ๋ณธ์œผ๋กœ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ, "Filters"์˜ ์—ญํ• ์„ ๋จผ์ € ๋ณด๋Š” ๊ฒƒ์ด ๋„์›€์ด๋œ๋‹ค.

์•„๋ž˜ ๊ทธ๋ฆผ์€ ํ•˜๋‚˜์˜ HTTP ์š”์ฒญ์—๋Œ€ํ•œ ํ•ธ๋“ค๋Ÿฌ์˜ ์œ ํ˜•๋ณ„๋กœ ๊ณ„์ฆ์ธต์„ ๋ณด์—ฌ์ค€๋‹ค. filter

ํด๋ผ์ด์–ธํŠธ๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•˜๋‚˜์˜ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์ปจํ…Œ์ด๋‚˜๋Š” ์–ด๋–ค ํ•„ํ„ฐ์™€ ์–ด๋–ค ์„œ๋ธ”๋ ›์„ ์ ์šฉํ• ์ง€๋ฅผ ์š”์ฒญ URI์˜ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒฐ์ •ํ•œ๋‹ค.

๋Œ€๊ฒŒ ํ•˜๋‚˜์˜ ์„œ๋ธ”๋ ›์€ ํ•˜๋‚˜์˜ ์š”์ฒญ์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•„ํ„ฐ๋Š” ์ฒด์ธ์œผ๋กœ ํ˜•์„ฑ๋˜๊ณ , ์ •๋ ฌ๋œ๋‹ค.

์‚ฌ์‹ค ํ•„ํ„ฐ๋Š” ๋งŒ์•ฝ์— ์š”์ฒญ์„ ์ž์ฒด์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธธ ์›ํ•˜๋ฉด, ๋‚˜๋จธ์ง€ ์ฒด์ธ์„ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•„ํ„ฐ๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต(๋‹ค์šด์ŠคํŠธ๋ฆผ ํ•„ํ„ฐ์™€ ์„œ๋ธ”๋ฆฟ์—์„œ ์‚ฌ์šฉ๋˜๋Š”)์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.(?)

ํ•„ํ„ฐ์ฒด์ธ์˜ ์ •๋ ฌ์€ ๊ต‰์žฅํžˆ ์ค‘์š”ํ•˜๋‹ค. ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์ด๊ฒƒ์„ ๋‘๊ฐ€์ง€ ๋งค์ปค๋‹ˆ์ฆ˜์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

@Beanํƒ€์ž…์˜ ํ•„ํ„ฐ๋Š” @Order๋ฅผ ๊ฐ–๊ฑฐ๋‚˜ Ordered๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ์–˜๋“ค์€ FilterRegisterationBean์˜ ํ•œ ๋ถ€๋ถ„์ด ๋  ์ˆ˜ ์žˆ๋‹ค. FilterRegisterationBean์€ ์Šค์Šค๋กœ ์ž์‹ ์˜ API์˜ ํ•œ ๋ถ€๋ถ„์œผ๋กœ ์š”์ฒญํ•œ๋‹ค.

์–ด๋–ค ๋งŒ๋“ค์–ด์ง„ ํ•„ํ„ฐ๋Š” ๋„์›€์š”์ฒญ(help signal)์— ์ถฉ์‹คํ•˜๊ฒŒ ์ •์˜๋˜์–ด์žˆ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด, Spring Session์˜SessionRepositoryFilter๋Š” "Integer.MIN_VALUE + 50"์˜ "DEFAULT_ORDER"๋ฅผ ๊ฐ–๋Š”๋‹ค.

์ด๋Š” ์ฒด์ธ์—์„œ ์ข€๋” ์•ž์„œ๊ณ  ์‹ถ์ง€๋งŒ, ๋‹ค๋ฅธ ํ•„ํ„ฐ๋“ค์ด ๋‚˜์˜ค๊ธฐ ์ „์— ๊ทœ์น™์„ ์–ด๊ธฐ์ง€ ์•Š๋Š”๋‹ค.

์Šคํ”„๋ง ์‹œํ๋Ÿฌํ‹ฐ๋Š” ์ฒด์ธ์—์„œ ํ•˜๋‚˜์˜ ํ•„ํ„ฐ๋กœ ์„ค์น˜๋˜์–ด์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Š” FilterChainProxyํƒ€์ž…์œผ๋กœ ๊ณ ์ •(concrete)์ด๋‹ค.

์Šคํ”„๋ง ๋ถ€ํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ, security ํ•„ํ„ฐ๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ์—์„œ @Bean์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์•ผ๋Š” ๊ธฐ๋ณธ์œผ๋กœ ์„ค์น˜๋˜์–ด์žˆ๊ณ , ๋ชจ๋“  ์š”์ฒญ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

security ํ•„ํ„ฐ๋Š” "SecurityProperties.DEFAULT_FILTER_ORDER" ์— ์˜ํ•ด ์ •์˜๋œ ์œ„์น˜์— ์„ค์น˜๋œ๋‹ค.

"SecurityProperties.DEFAULT_FILTER_ORDER"๋Š” "FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER"์—์˜ํ•ด ๊ณ ์ •๋œ๋‹ค.

(๋ญ๋ผ๋Š”๊ฑฐ์•ผ)

spring security filter

Spring Security๋Š” ํ•˜๋‚˜์˜ ๋ฌผ๋ฆฌ์ ์ธ ํ•„ํ„ฐ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๋ถ€ ํ•„ํ„ฐ๋“ค์˜ ์ฒด์ธ์— ๊ณผ์ •์„ ์œ„์ž„์‹œํ‚จ๋‹ค.

์‚ฌ์‹ค, security ํ•„ํ„ฐ์—์„œ ๊ฐ„์ ‘์ ์ธ ๊ณ„์ธต์ด ํ•˜๋‚˜ ๋” ์žˆ๋‹ค. ์–˜๋Š” "DelegatingFilterProxy"๋ผ๋Š” ์ปจํ…Œ์ด๋„ˆ์—์„œ ์„ค์น˜๋œ๋‹ค. ์–˜๋Š” Spring @Bean์ผ ํ•„์š”๊ฐ€ ์—†๋‹ค.

์ด ํ”„๋ก์‹œ๋Š” "FilterChainProxy"์—๊ฒŒ ์œ„์ž„์„ํ•œ๋‹ค. "FilterChainProxy"๋Š” ํ•ญ์ƒ @Bean์ด๊ณ , "springSecurityFilterChain"์ด๋ผ๋Š” ๊ณ ์ •๋œ ์ด๋ฆ„์„ ๊ฐ–๋Š”๋‹ค.

์ด "FilterChainProxy"๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ํ•„ํ„ฐ์˜ ์ฒด์ธ์œผ๋กœ ๊ตฌ์„ค๋œ ๋ณด์ธ ๋กœ์ง์„ ์ „๋ถ€ ํฌํ•จํ•œ๋‹ค.

๋ชจ๋“  ํ•„ํ„ฐ๋Š” ๊ฐ™์€ API๋ฅผ ๊ฐ–๋Š”๋‹ค.(ํ•„ํ„ฐ๋“ค์€ ์ „๋ถ€ ์„œ๋ธ”๋ฆฟ ์„ค๋ช…์„œ์˜ "Filter" ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„๋œ๋‹ค.), ๋ชจ๋“  ํ•„ํ„ฐ๋Š” ๋‚˜๋จธ์ง€ ์ฒด์ธ๋“ค์„ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐํšŒ๊ฐ€์žˆ๋‹ค.

"FilterChainProxy"์™€ ๊ฐ™์€ ํƒ‘๋ ˆ๋ฒจ์—์„œ Spring Security๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋ชจ๋“  ํ•„ํ„ฐ์ฒด์ธ์€ ๋งŽ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , ๋ชจ๋“œ ์ปจ์ฒด์ด๋„ˆ์—๊ฒŒ ์•Œ๋ ค์ง€์ง€ ์•Š๋Š”๋‹ค.

Spring Security ํ•„ํ„ฐ๋Š” ํ•„ํ„ฐ์ฒด์ธ์˜ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ–๊ณ ์žˆ๊ณ , ํ•„ํ„ฐ์™€ ๋งค์นญ๋˜๋Š” ์ฒซ๋ฒˆ์งธ ์ฒด์ธ๊ณผ ์š”์ฒญ์„ ๋ถ„๋ฆฌํ•œ๋‹ค.

์•„๋ž˜ ์ด๋ฏธ์ง€๋Š” ์š”์ฒญ ๊ฒฝ๋กœ ๋งค์นญ์— ๊ธฐ๋ฐ˜ํ•œ ๋ถ„๋ฆฌ(dispatch) ์ƒํ™ฉ์„ ๋ณด์—ฌ์ค€๋‹ค. ์ด๋Š” ์•„์ฃผ ์ผ๋ฐ˜์ ์ด์ง€๋งŒ ์š”์ฒญ์„ ๋งค์นญํ•˜๋Š”๊ฒƒ์ด ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค.

์ด ๋ถ„๋ฆฌ(dispatch) ๊ณผ์ •์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํŠน์ง•์€ ํ•˜๋‚˜์˜ ์ฒด์ธ๋งŒ์ด ์š”์ฒญ์„ ๋‹ค๋ฅธ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Security filters dispatch

Spring Security "FilterChainProxy"๋Š” ๋จผ์ € ๋งค์นญ๋˜๋Š” ์ฒซ๋ฒˆ์งธ ์ฒด์ธ์— ์š”์ฒญ์„ ๋ถ„๋ฆฌํ•œ๋‹ค.

์ปค์Šคํ…€ security ์„ค์ •์ด ์—†๋Š” vanilla Spring Boot ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ n๊ฐœ์˜ ํ•„ํ„ฐ ์ฒด์ธ์ด์žˆ๋‹ค. ๋ณดํ†ต n = 6.

์ฒซ๋ฒˆ์งธ ์ฒด์ธ(n-1)์€ static ์ž์›์˜ ํŒจํ„ด๋“ค์„ ๋ฌด์‹œํ•œ๋‹ค. (/css/, /images/, /error ๋ทฐ ๊ฐ™์€) (๊ทธ ๊ฒฝ๋กœ๋Š” SecurityProperties์—์„œ "security.ignored"๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.)

๋งˆ์ง€๋ง‰ ์ฒด์ธ์€ catch-all ๊ฒฝ๋กœ(/**) ๋งค์นญํ•˜๊ณ , ์ธ์ฆ์˜ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ , ์ธ๊ฐ€, ์˜ˆ์™ธ์ฒ˜๋ฆฌ, ์„ธ์…˜ ์ฒ˜๋ฆฌ, ํ—ค๋” ์ž‘์„ฑ ๋“ฑ๋“ฑ ๋” ๋งŽ์€ ์ž‘์—…์„ํ•œ๋‹ค.

๊ธฐ๋ณธ(default) ์ฒด์ธ์—์„œ ์ „๋ถ€ 11๊ฐœ์˜ ํ•„ํ„ฐ๊ฐ€ ์žˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž๋Š” ์–ด๋–ค ํ•„ํ„ฐ๊ฐ€ ์–ธ์ œ ์‚ฌ์šฉ๋˜๋Š”์ง€์— ๋Œ€ํ•œ ๊ฑฑ์ •์„ ํ•  ํ•„์š”๋Š” ์—†๋‹ค.

Spring Security ๋‚ด์˜ ๋ชจ๋“  ํ•„ํ„ฐ๋Š” ์‚ฌ์‹ค ์ปจํ…Œ์ด๋„ˆ์—๊ฒŒ ์•Œ๋ ค์ง€์ง€ ์•Š์•˜๋‹ค. ์ด๋Š” ์ค‘์š”ํ•˜๋‹ค. ํŠนํžˆ Spring Boot ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  Filter ํƒ€์ž…์˜ @Bean์€ ์ปจํ…Œ์ด๋„ˆ์— ์ž๋™์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ปค์Šคํ…€ ํ•„ํ„ฐ๋ฅผ security ์ฒด์ธ์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, @Bean์„ ๋งŒ๋“ค์ง€ ๋ง๊ฑฐ๋‚˜, ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋“ฑ๋ก์„ ๋ชฉํ•˜๋„๋ก ๋ช…์‹œ์ ์œผ๋กœ "FilterRegistrationBean"์œผ๋กœ ๊ฐ์‹ธ์•ผํ•œ๋‹ค.

ํ•„ํ„ฐ ํŽ˜์ธ์˜ ์ƒ์„ฑ๊ณผ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•

Spring Boot ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ธฐ๋ณธ ํ•„ํ„ฐ์ฒด์ธ์€ "SecurityProperties.BASIC_AUTH_ORDER"์˜ ์ฃผ๋ฌธ์—์˜ํ•ด ๋จผ์ € ์ •์˜๋˜์žˆ๋‹ค.

"security.basic.enabled=false" ์„ธํŒ…์„ ํ†ตํ•ด ์™„์ „ํžˆ ์„ค์ •์„ ๋Œ ์ˆ˜ ์žˆ๊ณ , ์•„๋‹ˆ๋ฉด ๋Œ€๋น„์ฑ…์œผ๋กœ ๊ธฐ๋ณธ์„ค์ •์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , ๋” ๋‚ฎ์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ–๋Š”(lower order) ๋‹ค๋ฅธ ๊ทœ์น™์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‚˜์ค‘์—, "WebSecurityConfigurerAdapter"๋˜๋Š” "WebSecurityConfigurer" ํƒ€์ž…์˜ @Bean์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  @Order๋ฅผ ์ด์šฉํ•ด ํด๋ž˜์Šค๋ฅผ ๋ฐ์ฝ”๋ ˆ์ดํŠธํ•  ์ˆ˜ ์žˆ๋‹ค.

โš ๏ธ spring security 5.7 "WebSecurityConfigurerAdapter" deprecated

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/match1/**")
                ...;
    }
}

์ด ๋นˆ์€ Spring Security๊ฐ€ ์ƒˆ๋กœ์šด ํ•„ํ„ฐ์ฒด์ธ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ธฐ๋ณธ ์„ค์ • ์ดํ›„์˜ ์šฐ์‚ฐ์ˆœ์œ„๋ฅผ ๊ฐ–๊ฒŒ์•ผ๊ธฐํ•œ๋‹ค.

๋งŽ์€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ฆฌ์†Œ์Šค ์ง‘ํ•ฉ์— ๋Œ€ํ•ด ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ ‘๊ทผ ๊ทœ์น™์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

๊ฐ ๋ฆฌ์†Œ์Šค์˜ ์„ธํŠธ๋Š” ์ž์‹ ๋“ค๋งŒ์˜ ์œ ์ผํ•œ ์ˆœ์„œ(order)์™€ ์š”์ฒญ ๋งค์นญ(request matcher)๊ณผ ํ•จ๊ป˜ "WebSecurityConfigurerAdapter"๋ฅผ ๊ฐ–๋Š”๋‹ค.

๋งŒ์•ฝ ๋งค์นญ๋ฃฐ๋ฆฌ ์˜ค๋ฒ„๋žฉ๋˜๋ฉด, ๊ฐ€์žฅ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์€ ํ•„ํ„ฐ์ฒด์ธ์ด ์ด๊ธด๋‹ค.

๋ถ„๋ฆฌ(Dispatch)์™€ ์ธ์ฆ์„ ์œ„ํ•œ ์š”์ฒญ ๋งค์น˜

security ํ•„ํ„ฐ ์ฒด์ธ(="WebSecurityConfigurerAdapter)์€ ์š”์ฒญ ๋งค์นญ(request matcher)์„ ๊ฐ–๋Š”๋‹ค. ์–˜๋Š” HTTP ์š”์ฒญ์— ์ด ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ• ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.

ํŠน์ • ํ•„ํ„ฐ ์ฒด์ธ์„ ์ ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •๋˜๋ฉด, ๋‹ค๋ฅธ ํ•„ํ„ฐ ์ฒด์ธ์€ ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.

ํ•„ํ„ฐ์ฒด์ธ์„ ์ ์šฉํ•˜๋ฉด, "HttpSecurity" ์„ค์ •์—์„œ ์ถ”๊ฐ€์ ์ธ ๋งค์นญ์„ ์„ธํŒ…ํ•˜๋ฉด ๋” ์„ฌ์„ธํ•˜๊ฒŒ ์ธ๊ฐ€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
    @Override
    protected  void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/match1/**")
                .authorizeRequests()
                .antMatchers("/match1/user").hasRole("USER")
                .antMatchers("/match1/spam").hasRole("SPAM")
                .anyRequest().isAuthenticated();
    }
}

ํŒŒ์ผ์—…๋กœ๋“œ

์Šคํ”„๋ง ๋ถ€ํŠธ MVC ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€(thymeleaf, spring-boot-starter-web ์ด ์ถ”๊ฐ€๋œ) ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” "MultipartConfigElement"๋ฅผ ๋“ฑ๋กํ•ด์•ผํ•œ๋‹ค. ์Šค๋ถ€๋Š” ๋ชจ๋‘ auto-config!

Flash Attribute

์ฐธ๊ณ  ์ž๋ฃŒ๋“ค

Thymeleaf๊ธฐ์ดˆ

controller์— ๋“ฑ๋ก๋œ html์€ templates/~์—์„œ ์ฐพ๋Š”๋‹ค.

formํƒœ๊ทธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” th:object="${greeting}" ํ‘œํ˜„์€ ํผ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋ธ ๊ฐ์ฒด๋Š” ์„ ์–ธํ•œ๋‹ค.

@, * ๊ฐ€๋ถ™์€ EL(?) ํ‘œํ˜„์‹์„ ์ž˜ ํŒŒ์•…ํ•ด ๋ณด์ž

Form Handling

์ฐธ๊ณ  : HelloController - greeting GET/POST

form ์š”์†Œ์—์„œ th:action="@{/greeting}" ํ‘œํ˜„์€ POST "/greeting"์—”๋“œํฌ์ธํŠธ๋กœ ๋ฐ”๋กœ๊ฐ„๋‹ค๋Š”๋ฐ.. ์•ˆ๊ฐ.

method="post" ๋„ฃ์–ด์ค˜์•ผ POST๋˜๋Š”๋””? ๊ธฐ๋ณธ์€ GET์œผ๋กœ ๊ฐ.

Validation ํ•˜๊ธฐ

gradle implementation 'org.springframework.boot:spring-boot-starter-validation'

๐Ÿ“• Errors, BindingResult ์ฃผ์˜ ์‚ฌํ•ญ

์Šˆํผ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋•Œ๋งค ๋˜ฅ๋ป˜์ง“ํ•˜๋‹ค ๋ฐœ๊ฒฌํ•œ ๋ฌธ์„œ ๋‚ด์šฉ

Errors, BindingResult: ๋˜๋Š”, @RequestBody, @RequestPart ์ธ์ž์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์™€ ๋ช…๋ น ๊ฐ์ฒด(@ModelAttribute ์ธ์ž)์— ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์—์„œ ์—๋Ÿฌ์— ์ ‘๊ทผํ•˜๊ธฐ์œ„ํ•ด ์‚ฌ์šฉ. "Errors", "BindingResult" ์ธ์ž๋Š” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์šฉ ๋ฉ”์†Œ๋“œ ์ธ์ž์˜ ์งํ›„์— ์œ„์น˜ํ•ด์•ผ๋˜๋Š”๊ฑธ ๋ฐ˜๋“œ์‹œ ํ™•์‹คํžˆํ•ด๋ผ

Thymeleaf Security

extras spring security

thymeleaf extras spring security extras springsecurity ์ž˜ ์ •๋ฆฌ๋œ ๋ฌธ์„œ

  • ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ฐ์ฒด ํ‘œํ˜„๋ฒ• ์‚ฌ์šฉ
<div th:text="${#authentication.name}">
  The value of the "name" property of the authentication object should appear here.
</div>
<div th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')')}">
  This will only be displayed if authenticated user has role ROLE_ADMIN.
</div>

#authorization๋Š” org.thymeleaf.extras.springsecurity[5|6].auth.Authorization์˜ ๊ฐ์ฒด์ด๋‹ค.

  • ์–ดํŠธ๋ฆฌ๋ทฐํŠธ ์‚ฌ์šฉํ•˜๊ธฐ sec:authentication ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” #authorization๋ž‘ ๊ฐ™๋‹ค. ์‚ฌ์šฉ๋ฒ•๋งŒ ๋‹ค๋ฆ„
<div sec:authentication="name">
  The value of the "name" property of the authentication object should appear here.
</div>

sec:authorize์™€ sec:authorize-expr์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋Š” ๊ฐ™๋‹ค. ์Šคํ”„๋ง ์‹œํ๋Ÿฌํ‹ฐ expression์—์„œ th:if๋Š” ์œ ํ‹ธ๋ฆฌํ‹ฐ ๊ฐ์ฒด ํ‘œํ˜„๋ฒ•์—์„œ #authorization.expression(...)์™€ ๊ฐ™์€๊ธฐ๋Šฅ ์ œ๊ณต.

  • ๋„ค์ž„์ŠคํŽ˜์ด์Šค dialect์˜ ๋ชจ๋“  ๋ฒ„์ „์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” http://www.thymeleaf.org/extras/spring-security์ด๋‹ค.

์ž˜๋ชป๋œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์€ ํ…œํ”Œ๋ฆฟ ์ฒ˜๋ฆฌ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์ง€๋งŒ, ํ…œํ”Œ๋ฆฟ์˜ ์ œ์•ˆ/์ž๋™์™„์„ฑ ๊ฐ™์€ IDE์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

Thymeleaf layout dialet

thymeleaf layout dialet ์ •๋ฆฌ ์ž˜ ๋œ ๋ฌธ์„œ

layout:decorate="~{layouts/default}" layout:decorate์„ ์‚ฌ์šฉํ–์„œ, ํŽ˜์ด์ง€๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค. ์–˜๋Š” ํŽ˜์ด์ง€์˜ ๋ฃจํŠธ ์š”์†Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

controller์—์„œ ์‘๋‹ตํŽ˜์ด์ง€๋Š” content ๊ฒฝ๋กœ๋ฅผ ์žก์•„์ฃผ๋ฉด๋œ๋‹ค. ํ—‰ํ—‰

์ปดํฌ๋„ŒํŠธ์Šค์บ”

Scope

  • @ComponentScan ์–ด๋…ธํ…Œ์ด์…˜์ด ์žˆ๋Š” ํŒŒ์ผ์˜ ํŒจํ‚ค์ง€ ์•„๋ž˜๋ฅผ ์ฐพ๋Š”๋‹ค.
  • basePackages / basePackageClasses๋กœ ์ง€์ •๋„ ๊ฐ€๋Šฅ
  • ๊ถŒ์žฅ ๋ฐฉ๋ฒ•: ๊ตฌ์„ฑํŒŒ์ผ์— ๋“ฑ๋ก์‹œ ํ”„๋กœ์ ํŠธ ์ตœ์ƒ๋‹จ์— ๋‘๊ธฐ.
    • SpringBoot๋Š” @SpringBootApplication์— ํฌํ•จ๋˜์–ด์žˆ์Œ.

๋นˆ ์ถฉ๋Œ ์ƒํ™ฉ

์ปดํฌ๋„ŒํŠธ ์Šค์บ”์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์Šคํ”„๋ง๋นˆ์ด ๋“ฑ๋ก๋˜๋Š”๋ฐ, ์ด๋•Œ ํด๋ž˜์Šค ์ด๋ฆ„์˜ ์•ž๊ธ€์ž๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ฐ”๊ฟ” ์Šคํ”„๋ง๋นˆ ๋“ฑ๋ก์ด ๋œ๋‹ค. ๊ทธ ์ด๋ฆ„์ด ๊ฐ™์€ ๊ฒฝ์šฐ ์Šคํ”„๋ง์€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

โ“ url mapping์ด ์žˆ์œผ๋ฉด ๋™์ž‘ํ•จ..;;;5

์ˆ˜๋™ ๋นˆ๊ณผ ์ž๋™ ๋นˆ์˜ ์ด๋ฆ„์ด ์ถฉ๋Œ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

โš ๏ธ Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true

๋นˆ ์ฃผ์ž…์‹œ ์ฃผ์ž… ๋Œ€์ƒ์ด ์—ฌ๋Ÿฌ๊ฐœ์ผ ๊ฒฝ์šฐ ์ถฉ๋Œ์ด ๋‚œ๋‹ค. @Qualifier, @Named, @Primary๋ฅผ ์‚ฌ์šฉํ•ด ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜์ž

์˜ต์…˜

ํŠน์ • ์–ด๋…ธํ…Œ์ด์…˜์„ ํฌํ•จ/์ œ์™ธ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ

  • includeFilters : ์ปดํฌ๋„ŒํŠธ ์Šค์บ” ๋Œ€์ƒ์œผ๋กœ ์ถ”๊ฐ€
  • excludeFilters : ~" ์ œ์™ธ
@ComponentScan(
        includeFilters = @ComponentScan.Filter(type = FilterType.Annotation, classes = IncludeComponent.class),
        excludeFilters = @ComponentScan.Filter(type = FilterType.Annotation, classes = OutcludeComponent.class)
)

FilterType ์˜ต์…˜

  • ANNOTATION : ๊ธฐ๋ณธ๊ฐ’, ์–ด๋…ธํ…Œ์ด์…˜์„ ์ธ์‹ํ•ด ๋™์ž‘
  • ASSIGNABLE_TYPE : ์ง€์ •ํ•œ ํƒ€์ž…๊ณผ ์ž์‹ ํƒ€์ž…์„ ์ธ์‹ํ•ด ๋™์ž‘
  • ASPECTJ : AspectJ ํŒจํ„ด ์‚ฌ์šฉ
  • REGEX : ์ •๊ทœ ํ‘œํ˜„์‹
  • CUSTOM : TypeFilter์ด๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ ์ฒ˜๋ฆฌ

๋ผ์ด๋ธŒํ…œํ”Œ๋ฆฟ ์„ธํŒ…

@org.junit.jupiter.api.Test
public void $EXPR$() {
    org.assertj.core.api.Assertions.assertThat($END$)
}

MockMvc Multipart POST request Test


ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ


์˜๋ฌธ ๋ฆฌ์ŠคํŠธ

Footnotes

  1. Java Management eXtension โ†ฉ

  2. Spring-boole-loader ๋ชจ๋“ˆ์€ ์‹คํ–‰๊ฐ€๋Šฅ jar์™€ warํŒŒ์ผ์„ ์ง€์›ํ•œ๋‹ค. Docs โ†ฉ

  3. Grape๋Š” Groovy์— ๋‚ด์žฅ๋˜์žˆ๋Š” JAR ์ข…์†์„ฑ ๋งค๋‹ˆ์ €์ด๋‹ค. Docs โ†ฉ

  4. โ†ฉ
  5. conclictController conflict2()๋™์ž‘ํ•จ. @GetMapping("!Captitalize")์žˆ๋‹ค๊ณ  ๋นˆ์ด ๋“ฑ๋ก๋จ... ๋ญฅ๋ฏธ? โ†ฉ

About

Java SpringBoot Study & Labs

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published