ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๐Ÿ“ƒ Introduction
ํ”„๋กœ์ ํŠธ์—์„œ ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋ฅผ ์ ์šฉํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  API ๊ฒฝ๋กœ๋Š” ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์น˜๊ฒŒ ํ•˜๊ณ , ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ์„ ํฌํ•จํ•œ ๋ช‡๋ช‡ API ๋Š” ์ธ์ฆ์ด ์—†์ด ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ด์•ผ ํ–ˆ๋‹ค. ๋ชจ๋“  API ๊ฐ€ ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์น˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š์•˜์œผ๋‚˜, ๋ช‡ ๊ฐœ์˜ API ๊ฐ€ ์ธ์ฆ์ด ์—†์ด๋„ ํ˜ธ์ถœ๋˜๋„๋ก ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ๊นŒ๋‹ค๋กœ์› ๋‹ค.

๐Ÿšฉ ํ˜„์žฌ ์ƒํ™ฉ

์•„๋ž˜๋Š” ํ˜„์žฌ ๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์˜ ๊ตฌ์„ฑ์ด๋‹ค. ๊ฐ๊ฐ ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ์„ ๋‚˜ํƒ€๋‚ด๋Š”
POST /api/v1/user/join ๊ณผ POST /api/v1/users/login ์„ antMatchers ์˜ permitAll() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด์„œ ์ธ์ฆ ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๊ฒŒ ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

๋ฌธ์ œ๋Š” GET api/v1/posts/** ๋˜ํ•œ ์ธ์ฆ ์—†์ด ํ˜ธ์ถœ๋˜๊ฒŒ ์„ค์ •ํ–ˆ๋‹ค๋Š” ์ ์—์„œ ๋ฐœ์ƒํ–ˆ๋‹ค.

์ด์œ ๋Š” ์•„๋ž˜์™€ ๊ฐ™์•˜๋‹ค:

  • ํ˜„์žฌ ์„ค์ •๋Œ€๋กœ๋ฉด ๊ฒฝ๋กœ๊ฐ€ api/v1/posts/ ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ชจ๋“  GET ๋ฐฉ์‹์˜ API ๋Š” ์ธ์ฆ ์ ˆ์ฐจ ์—†์ด ํ˜ธ์ถœ๋œ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ, ํ˜„ ์‹œ์ ์—์„œ ์ถ”๊ฐ€ํ•  API ๋Š” ๋กœ๊ทธ์ธ ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์ž์‹ ์ด ์ž‘์„ฑํ•œ ํฌ์ŠคํŠธ๋ฅผ ๋ชจ์•„์„œ ๋ณผ ์ˆ˜ ์žˆ๋Š” API์ธ
    GET api/v1/posts/my ์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๋ฏ€๋กœ, GET ๋ฐฉ์‹์˜ api/v1/posts/ ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ๋กœ์˜ API ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์ธ์ฆ ์ ˆ์ฐจ๋ฅผ ๊ฑฐ์น˜๋„๋ก ๋”ฐ๋กœ ์„ค์ •ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

์ฆ‰, ํ˜„์žฌ ์ƒํ™ฉ์—์„œ GET api/v1/posts/my ๋Š” ์ธ์ฆ ์—†์ด๋„ Authentication ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋˜์–ด ์žˆ์—ˆ๋‹ค.

Authentication ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

์ธ์ฆ์ด ๋˜์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ Authentication ๊ฐ์ฒด์˜ ๊ฐ’์€ null ์ด๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋˜์–ด ์žˆ์œผ๋ฉด, ์ธ์ฆ์ด ๋˜์ง€ ์•Š์•˜์„ ๋•Œ authentication.getName() ์—์„œ NullPointerException ์ด ๋ฐœ์ƒํ•œ๋‹ค. ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ธ์ฆ์ด ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ์ปค์Šคํ…€ ์—๋Ÿฌ์ธ INVALID\_PERMISSION ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ–ˆ๊ณ , ์ด๋Š” ๋กœ๊ทธ์ธ ์—†์ด๋Š” ์ ‘๊ทผ ์ž์ฒด๋ฅผ ํ—ˆ์šฉํ•˜์ง€ ์•Š์•„์•ผ ๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ์— ๋Œ€ํ•ด ๋ฐ˜ํ™˜๋  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ์ด๋‹ค.

Swagger ์—์„œ /api/v1/posts/my ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์—๋Ÿฌ ์ฝ”๋“œ 500์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
NullPointerException ์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐Ÿ”‘ ํ•ด๊ฒฐ

 

๊ทธ๋ž˜์„œ, ์šฐ์„  ํ˜„์žฌ /api/v1/posts/** ์˜ ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  GET API ๊ฒฝ๋กœ๋ฅผ ํ—ˆ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ api/v1/posts/my ๋ฅผ ์ œ์™ธํ•œ ํŠน์ • API ๊ฒฝ๋กœ๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ–ˆ๋‹ค. ๋ณ€๊ฒฝ ๋ฐฉ๋ฒ•์€ ์–ด๋ ต์ง€ ์•Š์•˜๋‹ค. ๋‹จ์ˆœํžˆ antMatchers() ๋‚ด๋ถ€์—์„œ ์‰ผํ‘œ(,) ๋ฅผ ์‚ฌ์šฉํ•ด ํ”„๋ฆฌํŒจ์Šค๋ฅผ ํ—ˆ์šฉํ•  API ๊ฒฝ๋กœ๋“ค์„ ๋ช…์‹œํ•ด์ฃผ๋ฉด ๋˜์—ˆ๋‹ค.

.antMatchers(HttpMethod.GET, "/api/v1/posts", "/api/v1/posts/{postId}",
            "/api/v1/posts/{postId}/comments").permitAll()

ํ•˜์ง€๋งŒ, Swagger ๋ฅผ ์‚ฌ์šฉํ•ด GET API ๋“ค์„ ํ˜ธ์ถœํ•ด๋ณด๋‹ˆ, ๋ณ€ํ•จ ์—†์ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ์œ„ ์ฝ”๋“œ๋กœ๋Š” GET api/v1/posts/my ์— ๋Œ€ํ•ด์„œ๋„ ์ธ์ฆ ์ ˆ์ฐจ ์—†์ด ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์˜๋ฏธ์˜€๋‹ค. ์ฐœ์ฐœํ–ˆ๋˜ ๋ถ€๋ถ„์ด {postId} ๋กœ API ๊ฒฝ๋กœ์˜ @PathVariable ๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด์–ด์„œ @PathVariable ์ด ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ antMatchers ์—์„œ ๋ช…์‹œํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ด ๋ฌด์—‡์ธ์ง€ ๊ฒ€์ƒ‰ํ•ด๋ณด์•˜๋‹ค:

stackoverflow ์—์„œ ๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค. @PathVariable ๋“ค์— ๋Œ€ํ•ด์„œ๋Š” {๋ณ€์ˆ˜๋ช…:<๋ฐ์ดํ„ฐ ํ˜•์— ๋”ฐ๋ฅธ ์ •๊ทœ์‹>} ํ˜•ํƒœ๋กœ ๋ช…์‹œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ๋ฐ”๋กœ ์ ์šฉํ•ด๋ณด์•˜๋‹ค:

.antMatchers(HttpMethod.GET, "/api/v1/posts", "/api/v1/posts/{postId:\\d+}",
            "/api/v1/posts/{postId:\\d+}/comments").permitAll()

postId ๋Š” ์ •์ˆ˜ํ˜• ๋ณ€์ˆ˜์˜€๊ธฐ ๋•Œ๋ฌธ์— ์ •๊ทœ์‹ \\d+ ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

์Šคํ”„๋ง ๊ณต์‹ ๋ฌธ์„œ์— ๋ฒ„์ “์ด @PathVariable ์— ๋Œ€ํ•œ antMatchers ์˜ ์‚ฌ์šฉ๋ฒ•์— ๋Œ€ํ•ด ๋ช…์‹œ๋˜์–ด ์žˆ๋‹ค.

๋‹ค์‹œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ž, ๋ฌธ์ œ ์—†์ด ๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์— GET api/v1/posts/my ๋Š” ์˜๋„ํ•œ INVALID_PERMISSION ์—๋Ÿฌ๋ฅผ ๋ƒˆ๊ณ , ๋‚˜๋จธ์ง€ GET API ๋“ค์€ ๋กœ๊ทธ์ธ ์—†์ด๋„ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค!

 

๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ชจ๋“  GET API ์ค‘ api/v1/posts/my ๋งŒ ์—๋Ÿฌ๋ฅผ ๋‚ธ๋‹ค.

 

๐Ÿ“Œ ์ถœ์ฒ˜

https://stackoverflow.com/questions/55863235/how-to-apply-spring-security-antmatchers-pattern-only-to-url-with-pathvariable

 

How to apply Spring Security AntMatchers pattern only to url with pathVariable

I am using Spring boot and WebSecurityConfigurerAdapter to configure security. Method to configure ignored security antMatches looks like this: @Override public void configure(final

stackoverflow.com

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html

 

AntPathMatcher (Spring Framework 6.0.3 API)

Combine two patterns into a new pattern. This implementation simply concatenates the two patterns, unless the first pattern contains a file extension match (e.g., *.html). In that case, the second pattern will be merged into the first. Otherwise, an Illega

docs.spring.io

๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/02   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
๊ธ€ ๋ณด๊ด€ํ•จ