[Security] Spring Security-Flow

Updated:

Categories:

Tags: ,

๐Ÿ“Œ ๊ฐœ์ธ์ ์ธ ๊ณต๊ฐ„์œผ๋กœ ๊ณต๋ถ€๋ฅผ ๊ธฐ๋กํ•˜๊ณ  ๋ณต์Šตํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ธ”๋กœ๊ทธ์ž…๋‹ˆ๋‹ค.
์ •ํ™•ํ•˜์ง€ ์•Š์€ ์ •๋ณด๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ๋ฐ”๋ž๋‹ˆ๋‹ค :๐Ÿ˜ธ
[ํ‹€๋ฆฐ ๋‚ด์šฉ์€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ๋ณต๋ฐ›์œผ์‹ค๊ฑฐ์—์š”]

Spring Security์˜ ํ๋ฆ„

๋ณด์•ˆ์ด ์ ์šฉ๋œ ์›น ์š”์ฒญ์˜ ์ผ๋ฐ˜์ ์ธ ์ฒ˜๋ฆฌ ํ๋ฆ„

  • (1)์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญ
  • (2)์—์„œ ์ธ์ฆ ๊ด€๋ฆฌ์ž ์—ญํ• ์„ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์˜ ํฌ๋ฆฌ๋ด์…œ(Credential)์„ ์š”์ฒญ
    • ์‚ฌ์šฉ์ž์˜ ํฌ๋ฆฌ๋ด์…œ(Credential) ์ด๋ž€ ํ•ด๋‹น ์‚ฌ์šฉ์ž๋ฅผ ์ฆ๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์ฒด์ ์ธ ์ˆ˜๋‹จ์„ ์˜๋ฏธ. ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ์‚ฌ์šฉ์ž์˜ ํŒจ์Šค์›Œ๋“œ๊ฐ€ ํฌ๋ฆฌ๋ด์…œ์— ํ•ด๋‹น
  • (3)์—์„œ ์‚ฌ์šฉ์ž๋Š” ์ธ์ฆ ๊ด€๋ฆฌ์ž์—๊ฒŒ ํฌ๋ฆฌ๋ด์…œ(Credential)์„ ์ œ๊ณต
  • (4)์—์„œ ์ธ์ฆ ๊ด€๋ฆฌ์ž๋Š” ํฌ๋ฆฌ๋ด์…œ ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉ์ž์˜ ํฌ๋ฆฌ๋ด์…œ์„ ์กฐํšŒ
  • (5)์—์„œ ์ธ์ฆ ๊ด€๋ฆฌ์ž๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ํฌ๋ฆฌ๋ด์…œ๊ณผ ํฌ๋ฆฌ๋ด์…œ ์ €์žฅ์†Œ์— ์ €์žฅ๋œ ํฌ๋ฆฌ๋ด์…œ์„ ๋น„๊ตํ•ด ๊ฒ€์ฆ ์ž‘์—…์„ ์ˆ˜ํ–‰
  • (6) ์œ ํšจํ•œ ํฌ๋ฆฌ๋ด์…œ์ด ์•„๋‹ˆ๋ผ๋ฉด Exception์„ throw ํ•œ๋‹ค.
  • (7) ์œ ํšจํ•œ ํฌ๋ฆฌ๋ด์…œ์ด๋ผ๋ฉด (8)์—์„œ ์ ‘๊ทผ ๊ฒฐ์ • ๊ด€๋ฆฌ์ž ์—ญํ• ์„ ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ ์ ˆํ•œ ๊ถŒํ•œ์„ ๋ถ€์—ฌ๋ฐ›์•˜๋Š”์ง€ ๊ฒ€์ฆ
  • (9) ์ ์ ˆํ•œ ๊ถŒํ•œ์„ ๋ถ€์—ฌ๋ฐ›์ง€ ๋ชปํ•œ ์‚ฌ์šฉ์ž๋ผ๋ฉด Exception์„ throwํ•œ๋‹ค.
  • (10) ์ ์ ˆํ•œ ๊ถŒํ•œ์„ ๋ถ€์—ฌ๋ฐ›์€ ์‚ฌ์šฉ์ž๋ผ๋ฉด ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ.

์›น ์š”์ฒญ์—์„œ์˜ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์™€ ํ•„ํ„ฐ ์ฒด์ธ์˜ ์—ญํ• 

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(Servlet Filter)

  • ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(Servlet Filter)๋Š” ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์—”๋“œํฌ์ธํŠธ์— ์š”์ฒญ์ด ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์ค‘๊ฐ„์—์„œ ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑˆ ํ›„ ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” Java์˜ ์ปดํฌ๋„ŒํŠธ

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋Š” ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” API์ด๋ฉฐ, javax.servlet ํŒจํ‚ค์ง€์— ์ธํ„ฐํŽ˜์ด์Šค ํ˜•ํƒœ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

javax.servlet.Filter ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋Š” ์›น ์š”์ฒญ(request)์„ ๊ฐ€๋กœ์ฑ„์–ด ์–ด๋–ค ์ฒ˜๋ฆฌ(์ „์ฒ˜๋ฆฌ)๋ฅผ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋˜ํ•œ ์—”๋“œํฌ์ธํŠธ์—์„œ ์š”์ฒญ ์ฒ˜๋ฆฌ๊ฐ€ ๋๋‚œ ํ›„ ์ „๋‹ฌ๋˜๋Š” ์‘๋‹ต(reponse)์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌํ•˜๊ธฐ ์ „์— ์–ด๋–ค ์ฒ˜๋ฆฌ(ํ›„์ฒ˜๋ฆฌ)๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Filter์—์„œ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ๋ชจ๋‘ ์™„๋ฃŒ๋˜๋ฉด DispatcherServlet์—์„œ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ํ•ธ๋“ค๋Ÿฌ์— ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•œ ๋‹ค์Œ ์ž‘์—…์„ ์ง„ํ–‰

ํ•„ํ„ฐ์ฒด์ธ

Spring Security์—์„œ ๋ณด์•ˆ์„ ์œ„ํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•„ํ„ฐ์˜ ๋ชจ์Œ

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ ํ•„ํ„ฐ๋“ค์„ ์—ฐ๊ฒฐํ•ด ํ•„ํ„ฐ ์ฒด์ธ(Filter Chain)์„ ๊ตฌ์„ฑ

  • ๊ฐ์˜ ํ•„ํ„ฐ๋“ค์ด doFilter()๋ผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋ฉฐ, doFilter() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์„ ํ†ตํ•ด ํ•„ํ„ฐ ์ฒด์ธ์„ ํ˜•์„ฑ
    • doFilter()๋Š” Filter์—์„œ ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์‹œ์ž‘์ 
  • Filter ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๋‹ค์ˆ˜์˜ Filter ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์—์„œ ํŠน๋ณ„ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ ๋’ค, HttpServlet์„ ๊ฑฐ์ณ DispatcherServlet์— ์š”์ฒญ์ด ์ „๋‹ฌ๋˜๋ฉฐ, ๋ฐ˜๋Œ€๋กœ DispatcherServlet์—์„œ ์ „๋‹ฌํ•œ ์‘๋‹ต์— ๋Œ€ํ•ด ์—ญ์‹œ ํŠน๋ณ„ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Servlet FilterChain์€ ์š”์ฒญ URI path๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ HttpServletRequest๋ฅผ ์ฒ˜๋ฆฌ โ‡’ ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„ ์ธก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์š”์ฒญ์„ ์ „์†กํ•˜๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๋Š” ์š”์ฒญ URI์˜ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์–ด๋–ค Filter์™€ ์–ด๋–ค Servlet์„ ๋งคํ•‘ํ• ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
  • Filter Chain์—์„œ Filter์˜ ์ˆœ์„œ๋Š” ๋งค์šฐ ์ค‘์š”ํ•˜๋ฉฐ Spring Boot์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ Filter๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ ์šฉ๊ฐ€๋Šฅ
    • Spring Bean์œผ๋กœ ๋“ฑ๋ก๋˜๋Š” Filter์—ย @Order ์• ๋„ˆํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ย Orderd ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์„œ Filter์˜ ์ˆœ์„œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • FilterRegistrationBean์„ ์ด์šฉํ•ด Filter์˜ ์ˆœ์„œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Spring Security์—์„œ์˜ ํ•„ํ„ฐ ์—ญํ• 

  • Spring Security์—์„œ ์ง€์›ํ•˜๋Š” Filter ์ข…๋ฅ˜๋Š” ๋ฌด์ˆ˜ํžˆ ๋งŽ๋‹ค.
  • Spring Security ํ•„ํ„ฐ ์ค‘ ํŠน๋ณ„ํ•œ ํ•„ํ„ฐ : DelegatingFilterProxy , FilterChainProxy

    DelegatingFilterProxy์™€ FilterChainProxy ํด๋ž˜์Šค๋Š” Filter ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ๋กœ์จ์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

1. DelegatingFilterProxy โญ

Spring Security๋Š” Spring์˜ ํ•ต์‹ฌ์ธ ApplicationContext๋ฅผ ์ด์šฉ ํ•œ๋‹ค.

์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ์™€ ์—ฐ๊ฒฐ๋˜๋Š” Spring Security๋งŒ์˜ ํ•„ํ„ฐ๋ฅผ ApplicationContext์— Bean์œผ๋กœ ๋“ฑ๋กํ•œ ํ›„์— ์ด Bean๋“ค์„ ์ด์šฉํ•ด์„œ ๋ณด์•ˆ๊ณผ ๊ด€๋ จ๋œ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋Š”๋ฐ DelegatingFilterProxy ๊ฐ€ Bean์œผ๋กœ ๋“ฑ๋ก๋œ Spring Security์˜ ํ•„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ž‘์  ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ DelegatingFilterProxy ๋Š” ๋ณด์•ˆ๊ณผ ๊ด€๋ จ๋œ ์–ด๋–ค ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์˜์—ญ์˜ ํ•„ํ„ฐ์™€ ApplicationContext์— Bean์œผ๋กœ ๋“ฑ๋ก๋œ ํ•„ํ„ฐ๋“ค์„ ์—ฐ๊ฒฐํ•ด ์ฃผ๋Š” ๋ธŒ๋ฆฌ์ง€ ์—ญํ• ์„ ํ•œ๋‹ค.

2. FilterChainProxy โญ

  • Spring Security์˜ Filter๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ง„์ž…์ 
  • FilterChainProxy๋ถ€ํ„ฐ Spring Security์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ณด์•ˆ ํ•„ํ„ฐ๋“ค์ด ํ•„์š”ํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค
  • Spring Security์˜ Filter Chain์€ URL ๋ณ„๋กœ ์—ฌ๋Ÿฌ ๊ฐœ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Filter Chain์ด ์žˆ์„ ๋•Œ ์–ด๋–ค Filter Chain์„ ์‚ฌ์šฉํ• ์ง€๋Š” FilterChainProxy๊ฐ€ ๊ฒฐ์ •ํ•˜๋ฉฐ, ๊ฐ€์žฅ ๋จผ์ € ๋งค์นญ๋œ Filter Chain์„ ์‹คํ–‰
    • /api/** ํŒจํ„ด์˜ Filter Chain์ด ์žˆ๊ณ , /api/message URL ์š”์ฒญ์ด ์ „์†กํ•˜๋Š” ๊ฒฝ์šฐ
      • /api/** ํŒจํ„ด๊ณผ ์ œ์ผ ๋จผ์ € ๋งค์นญ๋˜๋ฏ€๋กœ, ๋””ํดํŠธ ํŒจํ„ด์ธ /**๋„ ์ผ์น˜ํ•˜์ง€๋งŒ ๊ฐ€์žฅ ๋จผ์ € ๋งค์นญ๋˜๋Š” /api/** ํŒจํ„ด๊ณผ ์ผ์น˜ํ•˜๋Š” Filter Chain๋งŒ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    • /message/** ํŒจํ„ด์˜ Filter Chain์ด ์—†๋Š”๋ฐ /message/ URL ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ๊ฒฝ์šฐ - ๋งค์นญ๋˜๋Š” Filter Chain์ด ์—†์œผ๋ฏ€๋กœ ๋””ํดํŠธ ํŒจํ„ด์ธ /** ํŒจํ„ด์˜ Filter Chain์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ์ œ

    • ์—ฌ๊ธฐ์„œ ํ•˜๋‚˜ํ•˜๋‚˜๊ฐ€ ๋‹ค ํ•„ํ„ฐ๊ฐ€ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ ๊ฐ๊ฐ ํ•˜๋‚˜์˜ ํ•„ํ„ฐ์— ๋งตํ•‘๋œ๋‹ค.
    • SpringSecurity์—์„œ ์ง€์›ํ•˜๋Š” Filter์˜ ์ข…๋ฅ˜๊ฐ€ ์ •๋ง ๋งŽ๊ณ  ๋‚ด๊ฐ€ ์ƒˆ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•  ์ผ์€ ์ž˜ ์—†๋‹ค. โ†’ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ ์–ด๋А๋ถ€๋ถ„์ด ์ž˜๋ชป๋˜์—ˆ๋Š”์ง€๋งŒ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์œผ๋ฉด ๋จ.



Filter ์ธํ„ฐํŽ˜์ด์Šค

filter๋Š” init์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์ถ”์ƒ๋ฉ”์„œ๋“œ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

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
public class FirstFilter implements Filter {
     // (1) ์ดˆ๊ธฐํ™” ์ž‘์—…
     public void init(FilterConfig filterConfig) throws ServletException {

     }

     // (2)  ํ•ด๋‹น Filter๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹ค์งˆ์ ์ธ ๋กœ์ง์„ ๊ตฌํ˜„
     public void doFilter(ServletRequest request,
                          ServletResponse response,
                          FilterChain chain)
                          throws IOException, ServletException {
        // (2-1) ์ด๊ณณ์—์„œ request(ServletRequest)๋ฅผ ์ด์šฉํ•ด ๋‹ค์Œ Filter๋กœ ๋„˜์–ด๊ฐ€๊ธฐ ์ „์ฒ˜๋ฆฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

         // (2-2)
        chain.doFilter(request, response);

        // (2-3)์—์„œ response๋ฅผ ์ด์šฉํ•ด (2-2)์˜ chain.doFilter(request, response)๊ฐ€ ํ˜ธ์ถœ๋œ ์ดํ›„์— ํ•  ์ˆ˜ ์žˆ๋Š” ํ›„์ฒ˜๋ฆฌ ์ž‘์—…์— ๋Œ€ํ•œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ
     }

    
     public void destroy() {
        // (5) Filter๊ฐ€ ์‚ฌ์šฉํ•œ ์ž์›์„ ๋ฐ˜๋‚ฉํ•˜๋Š” ์ฒ˜๋ฆฌ
     }
  }



Spring Security์˜ ์ธ์ฆ ์ปดํฌ๋„ŒํŠธ

UsernamePasswordAuthenticationFilter

์ผ๋ฐ˜์ ์œผ๋กœ ๋กœ๊ทธ์ธ ํผ์—์„œ ์ œ์ถœ๋˜๋Š” Username๊ณผ Password๋ฅผ ํ†ตํ•œ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Filter

Untitled

  • AbstractAuthenticationProcessingFilter๋ฅผ ์ƒ์†
  • 1 : ํด๋ผ์ด์–ธํŠธ์˜ ๋กœ๊ทธ์ธ ํผ์„ ํ†ตํ•ด ์ „์†ก๋˜๋Š” request parameter์˜ ๋””ํดํŠธ name์€ username๊ณผ password
  • 2 : AntPathRequestMatcher๋Š” ํด๋ผ์ด์–ธํŠธ์˜ URL์— ๋งค์น˜๋˜๋Š” ๋งค์ฒ˜ โ†’ ํด๋ผ์ด์–ธํŠธ์˜ URL์ด โ€œ/loginโ€œ์ด๊ณ , HTTP Method๊ฐ€ POST์ผ ๊ฒฝ์šฐ ๋งค์น˜๋  ๊ฑฐ๋ผ๋Š” ์‚ฌ์‹ค์„ ์˜ˆ์ธก๊ฐ€๋Šฅ
  • AntPathRequestMatcher์˜ ๊ฐ์ฒด(DEFAULT_ANT_PATH_REQUEST_MATCHER)๋Š” ๋…ธ๋ž€ ๋ฐ•์Šค์— ์žˆ๋Š” 4๋ฒˆ ์—์„œ ์ƒ์œ„ ํด๋ž˜์Šค์ธ AbstractAuthenticationProcessingFilter ํด๋ž˜์Šค์— ์ „๋‹ฌ๋˜์–ด Filter๊ฐ€ ๊ตฌ์ฒด์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ• ์ง€ ํŠน๋ณ„ํ•œ ์ž‘์—… ์—†์ด ๋‹ค๋ฅธ Filter๋ฅผ ํ˜ธ์ถœํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ
  • ๋ถ„ํ™๋ฐ•์Šค์— ํ•ด๋‹นํ•˜๋Š” 5๋ฒˆ์˜ attemptAuthentication() ๋ฉ”์„œ๋“œ๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์—์„œ๋„ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์ „๋‹ฌํ•œ username๊ณผ password ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์ธ์ฆ์„ ์‹œ๋„ํ•˜๋Š” ๋ฉ”์„œ๋“œ
    • attemptAuthentication() ๋ฉ”์„œ๋“œ๋Š” ์ƒ์œ„ ํด๋ž˜์Šค์ธ AbstractAuthenticationProcessingFilter์˜ doFilter() ๋ฉ”์„œ๋“œ์—์„œ ํ˜ธ์ถœ๋œ๋‹ค.
    • HTTP Method๊ฐ€ POST๊ฐ€ ์•„๋‹ˆ๋ฉด Exception์„ throwํ•œ๋‹ค
    • username๊ณผ password ์ •๋ณด๋ฅผ ์ด์šฉํ•ด UsernamePasswordAuthenticationToken์„ ์ƒ์„ฑ ( UsernamePasswordAuthenticationToken์€ ์ธ์ฆ์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ์ธ์ฆ ํ† ํฐ์ด์ง€ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ธ์ฆ ํ† ํฐ๊ณผ๋Š” ์ƒ๊ด€์ด ์—†๋‹ค)
  • doFilter() ๋Š” ์ƒ์œ„ํด๋ž˜์Šค์ธAbstractAuthenticationProcessingFilter๊ฐ€ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค.

AbstractAuthenticationProcessingFilter

HTTP ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ ์‹ค์งˆ์ ์ธ ์ธ์ฆ ์‹œ๋„๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์— ๋งก๊ธฐ๊ณ , ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ SecurityContext์— ์ €์žฅํ•˜๋Š” ์—ญํ• 

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public abstract class AbstractAuthenticationProcessingFilter extends 
	GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        this.doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);
    }
	
	// (1)
    private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
       // (1-1)  ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•„๋‹ˆ๋ฉด ๋‹ค์Œ Filter๋ฅผ ํ˜ธ์ถœํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •
        if (!this.requiresAuthentication(request, response)) {
            chain.doFilter(request, response);
        } else {
            try {
                Authentication authenticationResult = this.attemptAuthentication(request, response); 
               // (1-2) ํ•˜์œ„ ํด๋ž˜์Šค (UsernamePasswordAuthenticationFilter )์—์„œ ์ธ์ฆ์„ ์‹œ๋„ํ•ด ์ค„ ๊ฒƒ์„ ์š”
                if (authenticationResult == null) {
                    return;
                }

                this.sessionStrategy.onAuthentication(authenticationResult, request, response);
                
                // Authentication success
                if (this.continueChainBeforeSuccessfulAuthentication) {
                    chain.doFilter(request, response);
                }

                this.successfulAuthentication(request, response, chain, authenticationResult);
                // (1-3) ์ธ์ฆ์— ์„ฑ๊ณตํ•˜๋ฉด ์ฒ˜๋ฆฌํ•  ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด (3) successfulAuthentication() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœ
               
                
            } catch (InternalAuthenticationServiceException var5) {
                InternalAuthenticationServiceException failed = var5;
                this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
                this.unsuccessfulAuthentication(request, response, failed); 
                // (1-4) ๋งŒ์•ฝ ์ธ์ฆ์— ์‹คํŒจํ•œ๋‹ค๋ฉด (4) unsuccessfulAuthentication() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ธ์ฆ ์‹คํŒจ ์‹œ ์ฒ˜๋ฆฌํ•  ๋™์ž‘์„ ์ˆ˜ํ–‰
	               
               
               // Authentication failed 
            } catch (AuthenticationException var6) {
                AuthenticationException ex = var6;
                this.unsuccessfulAuthentication(request, response, ex);
            }

        }
    }

		// (2) requiresAuthenticationRequestMatcher ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด **๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์ด ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •**
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        if (this.requiresAuthenticationRequestMatcher.matches(request)) {
            return true;
        } else {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace(LogMessage.format("Did not match request to %s", this.requiresAuthenticationRequestMatcher));
            }

            return false;
        }
    }

    public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException;

	  // (3) ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ดํ›„, **SecurityContextHolder๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ SecurityContext์— ์ €์žฅํ•œ ๋’ค,  SecurityContext๋ฅผ HttpSession์— ์ €์žฅ**
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        SecurityContextHolder.setContext(context);
        this.securityContextRepository.saveContext(context, request, response);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
        }

        this.rememberMeServices.loginSuccess(request, response, authResult);
        if (this.eventPublisher != null) {
            this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }

        this.successHandler.onAuthenticationSuccess(request, response, authResult);
    }
    
    // (4) ์ธ์ฆ ์‹คํŒจ์‹œ  SeucurityContext๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ณ , AuthenticationFailureHandler๋ฅผ ํ˜ธ์ถœ
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        this.logger.trace("Failed to process authentication request", failed);
        this.logger.trace("Cleared SecurityContextHolder");
        this.logger.trace("Handling authentication failure");
        this.rememberMeServices.loginFail(request, response);
        this.failureHandler.onAuthenticationFailure(request, response, failed);
    }
		 ...
		 ...
}

  • ์—ฌ๊ธฐ์„œ this๋Š” ์›๋ž˜ AbstractAuthenticationProcessingFilter ํด๋ž˜์Šค์˜ ํ˜„์žฌ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜์ง€๋งŒ, ์ถ”์ƒํด๋ž˜์Šค ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ์ธ์Šคํ„ด์Šคํ™” ๋˜์ง€ ์•Š๊ณ  ์ด๋ฅผ ์ƒ์†๋ฐ›์€ ํ•˜์œ„ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ์ƒ์†๋ฐ›์€ ํ•˜์œ„ํด๋ž˜์Šค์— ํ•ด๋‹นํ•˜๋Š” UsernamePasswordAuthenticationFilter์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋œ๋‹ค.
  • ์ฆ‰, this๋Š” AbstractAuthenticationProcessingFilter ํด๋ž˜์Šค์˜ ํ•˜์œ„ํด๋ž˜์Šค (UsernamePasswordAuthenticationFilter)์— ํ•ด๋‹นํ•จ.

UsernamePasswordAuthenticationToken

Spring Security์—์„œ Username/Password๋กœ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ํ† ํฐ์ด๋ฉฐ, ๋˜ํ•œ ์ธ์ฆ ์„ฑ๊ณต ํ›„ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๊ฐ€ UsernamePasswordAuthenticationToken์— ํฌํ•จ๋˜์–ด Authentication ๊ฐ์ฒด ํ˜•ํƒœ๋กœ SecurityContext์— ์ €์žฅ๋œ๋‹ค.

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
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
	...

	private final Object principal;

	private Object credentials;

  ...
  ...

  // (1) **์ธ์ฆ์— ํ•„์š”ํ•œ ์šฉ๋„์˜ UsernamePasswordAuthenticationToken ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ**
	public static UsernamePasswordAuthenticationToken unauthenticated(Object principal, Object credentials) {
		return new UsernamePasswordAuthenticationToken(principal, credentials);
	}

  // (2) **์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ดํ›„ SecurityContext์— ์ €์žฅ๋  UsernamePasswordAuthenticationToken ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ**
	public static UsernamePasswordAuthenticationToken authenticated(Object principal, Object credentials,
			Collection<? extends GrantedAuthority> authorities) {
		return new UsernamePasswordAuthenticationToken(principal, credentials, authorities);
	}

  ...
  ...

}

  • UsernamePasswordAuthenticationToken์€ AbstractAuthenticationToken์„ ์ƒ์†ํ•˜๋Š” ํ™•์žฅํด๋ž˜์Šค์ด์ž, Authentication ์ธํ„ฐํŽ˜์ด์Šค์˜ ๋ฉ”์„œ๋“œ ์ผ๋ถ€๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„ ํด๋ž˜์Šค์ด๋‹ค.

Authentication

Spring Security์—์„œ์˜ ์ธ์ฆ ์ž์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค

1
2
3
4
5
6
7
8
9
public interface Authentication extends Principal, Serializable {
	Collection<? extends GrantedAuthority> getAuthorities();
	Object getCredentials();
	Object getDetails();
	Object getPrincipal();
	boolean isAuthenticated();
	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

  • Principal
    • Principal์€ ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์ •๋ณด

    ์ผ๋ฐ˜์ ์œผ๋กœ Username/Password ๊ธฐ๋ฐ˜ ์ธ์ฆ์—์„œ Username์ด Principal์ด ๋˜๋ฉฐ, ๋‹ค๋ฅธ ์ธ์ฆ ๋ฐฉ์‹์—์„œ๋Š” UserDetails๊ฐ€ Principal์ด ๋œ๋‹ค

  • Credentials
    • ์‚ฌ์šฉ์ž ์ธ์ฆ์— ํ•„์š”ํ•œ Password๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ ์ธ์ฆ์ด ์ด๋ฃจ์–ด์ง€๊ณ  ๋‚œ ์งํ›„, ProviderManager๊ฐ€ ํ•ด๋‹น Credentials๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
  • Authorities
    • AuthenticationProvider์— ์˜ํ•ด ๋ถ€์—ฌ๋œ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ ๊ถŒํ•œ ๋ชฉ๋ก์ด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ GrantedAuthority ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋Š” SimpleGrantedAuthority

AuthenticationManager

์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์ด๊ด„ํ•˜๋Š” ๋งค๋‹ˆ์ € ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค

1
2
3
4
5
public interface AuthenticationManager {

//authenticate() ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋งŒ ์ •์˜๋˜์–ด ์žˆ๋‹ค.
	Authentication authenticate(Authentication authentication) throws AuthenticationException;
}
  • ๋А์Šจํ•œ ๊ฒฐํ•ฉ์„ ์œ ์ง€ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ธ์ฆ์„ ์œ„ํ•œ ์‹ค์งˆ์ ์ธ ๊ด€๋ฆฌ๋Š” AuthenticationManager๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด ์ง„๋‹ค.

ProviderManager

AuthenticationManager ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋ผ๊ณ  ํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ProviderManager๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

AuthenticationProvider๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , AuthenticationProvider์—๊ฒŒ ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๋Š” ์—ญํ• 

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
  ...
  ...

  // (1) ProviderManager ํด๋ž˜์Šค๊ฐ€ Bean์œผ๋กœ ๋“ฑ๋ก ์‹œ, List<AuthenticationProvider> **๊ฐ์ฒด๋ฅผ DI ๋ฐ›๋Š”๋‹ค**๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜์žˆ๋‹ค.
	public ProviderManager(List<AuthenticationProvider> providers, AuthenticationManager parent) {
		Assert.notNull(providers, "providers list cannot be null");
		this.providers = providers;
		this.parent = parent;
		checkState();
	}

  ...
  ...

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Class<? extends Authentication> toTest = authentication.getClass();
		AuthenticationException lastException = null;
		AuthenticationException parentException = null;
		Authentication result = null;
		Authentication parentResult = null;
		int currentPosition = 0;
		int size = this.providers.size();

    // (2) DI ๋ฐ›์€ List<AuthenticationProvider>๋ฅผ ์ด์šฉํ•ด (2)์™€ ๊ฐ™์ด for๋ฌธ์œผ๋กœ **์ ์ ˆํ•œ AuthenticationProvider๋ฅผ ์ฐพ๋Š”๋‹ค.**
		
		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {
				continue;
			}
			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format("Authenticating request with %s (%d/%d)",
						provider.getClass().getSimpleName(), ++currentPosition, size));
			}
			try {
				result = provider.authenticate(authentication);  
				// (3) AuthenticationProvider๋ฅผ ์ฐพ์•˜๋‹ค๋ฉด (3)๊ณผ ๊ฐ™์ด ํ•ด๋‹น **AuthenticationProvider์—๊ฒŒ ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„**
				
				
				if (result != null) {
					copyDetails(authentication, result);
					break;
				}
			}
			catch (AccountStatusException | InternalAuthenticationServiceException ex) {
				prepareException(ex, authentication);
				throw ex;
			}
			catch (AuthenticationException ex) {
				lastException = ex;
			}
		}

		...
    ...

		if (result != null) {
			if (this.eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
				((CredentialsContainer) result).eraseCredentials(); 
					 // (4)์ธ์ฆ์ด ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์—ˆ๋‹ค๋ฉด **์ธ์ฆ์— ์‚ฌ์šฉ๋œ Credentials๋ฅผ ์ œ๊ฑฐ**
			}

			if (parentResult == null) {
				this.eventPublisher.publishAuthenticationSuccess(result);
			}

			return result;
		}

    ...
    ...
	}

  ...
  ...
}

AuthenticationProvider

AuthenticationManager๋กœ๋ถ€ํ„ฐ ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„๋ฐ›์•„ ์‹ค์งˆ์ ์ธ ์ธ์ฆ ์ˆ˜ํ–‰์„ ๋‹ด๋‹นํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ

Username/Password ๊ธฐ๋ฐ˜์˜ ์ธ์ฆ ์ฒ˜๋ฆฌ๋Š” DaoAuthenticationProvider๊ฐ€ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, DaoAuthenticationProvider๋Š” UserDetailsService๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ UserDetails๋ฅผ ์ด์šฉํ•ด ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { 
					 // (1) AbstractUserDetailsAuthenticationProvider๋ฅผ ์ƒ์†
  ...
	private PasswordEncoder passwordEncoder;

	...
  ...

  // (2) UserDetailsService๋กœ๋ถ€ํ„ฐ UserDetails๋ฅผ ์กฐํšŒํ•˜๋Š” ์—ญํ• 
  //  ์กฐํšŒ๋œ **UserDetails๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ธ์ฆ์— ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ, ์ธ์ฆ๋œ Authentication ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ**
	@Override
	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		prepareTimingAttackProtection();
		try {
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username); 
					    // (2-1) UserDetails๋ฅผ ์กฐํšŒ
					    
			if (loadedUser == null) {
				throw new InternalAuthenticationServiceException(
						"UserDetailsService returned null, which is an interface contract violation");
			}
			return loadedUser;
		}
		catch (UsernameNotFoundException ex) {
			mitigateAgainstTimingAttack(authentication);
			throw ex;
		}
		catch (InternalAuthenticationServiceException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

  // (3) PasswordEncoder๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž์˜ ํŒจ์Šค์›Œ๋“œ๋ฅผ ๊ฒ€์ฆํ•˜
	@Override
	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
		if (authentication.getCredentials() == null) {
			this.logger.debug("Failed to authenticate since no credentials provided");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
		String presentedPassword = authentication.getCredentials().toString();
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) { 
							// (3-1)  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒํ•œ ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ
							
			this.logger.debug("Failed to authenticate since password does not match stored value");
			throw new BadCredentialsException(this.messages
					.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
		}
	}

  ...
  ...
}

  • AuthenticationProvider ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋Š” AbstractUserDetailsAuthenticationProvider์ด๊ณ , DaoAuthenticationProvider๋Š” AbstractUserDetailsAuthenticationProvider๋ฅผ ์ƒ์†ํ•œ ํ™•์žฅ ํด๋ž˜์Šค์ด๋‹ค.
  • โญ ๋”ฐ๋ผ์„œ AbstractUserDetailsAuthenticationProvider ์ถ”์ƒ ํด๋ž˜์Šค์˜ authenticate() ๋ฉ”์„œ๋“œ์—์„œ๋ถ€ํ„ฐ ์‹ค์งˆ์ ์ธ ์ธ์ฆ ์ฒ˜๋ฆฌ๊ฐ€ ์‹œ์ž‘๋œ๋‹ค
  • DaoAuthenticationProvider์™€ AbstractUserDetailsAuthenticationProvider์˜ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์ˆœ์„œ๊ฐ€ ์ค‘์š”
    • ๋‘ ํด๋ž˜์Šค๊ฐ€ ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉด์„œ ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋กœ์ง์„ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์ง€ ์•Š์Œ
      1. AbstractUserDetailsAuthenticationProvider์˜ authenticate() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
      2. DaoAuthenticationProvider์˜ retrieveUser() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
      3. DaoAuthenticationProvider์˜ additionalAuthenticationChecks() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
      4. DaoAuthenticationProvider์˜ createSuccessAuthentication() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
      5. AbstractUserDetailsAuthenticationProvider์˜ createSuccessAuthentication() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
      6. ์ธ์ฆ๋œ Authentication์„ ProviderManager์—๊ฒŒ ๋ฆฌํ„ด

UserDetails

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ์˜ ์ €์žฅ์†Œ์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž์˜ Username๊ณผ ์‚ฌ์šฉ์ž์˜ ์ž๊ฒฉ์„ ์ฆ๋ช…ํ•ด ์ฃผ๋Š” ํฌ๋ฆฌ๋ด์…œ(Credential)์ธ Password ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๋ฉฐ, AuthenticationProvider๋Š” UserDetails๋ฅผ ์ด์šฉํ•ด ์ž๊ฒฉ ์ฆ๋ช…์„ ์ˆ˜ํ–‰

1
2
3
4
5
6
7
8
9
10
11
12
public interface UserDetails extends Serializable {

	Collection<? extends GrantedAuthority> getAuthorities(); // (1) ๊ถŒํ•œ ์ •๋ณด
	String getPassword(); // (2) ํŒจ์Šค์›Œ๋“œ
	String getUsername(); // (3) Username

	boolean isAccountNonExpired();  // (4) ์‚ฌ์šฉ์ž ๊ณ„์ •์˜ ๋งŒ๋ฃŒ ์—ฌ๋ถ€
	boolean isAccountNonLocked();   // (5) ์‚ฌ์šฉ์ž ๊ณ„์ •์˜ lock ์—ฌ๋ถ€
	boolean isCredentialsNonExpired(); // (6) Credentials(Password)์˜ ๋งŒ๋ฃŒ ์—ฌ๋ถ€
	boolean isEnabled();               // (7) ์‚ฌ์šฉ์ž์˜ ํ™œ์„ฑํ™” ์—ฌ๋ถ€
}

UserDetailsService

UserDetails๋ฅผ ๋กœ๋“œ(load)ํ•˜๋Š” ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค

1
2
3
4
5
public interface UserDetailsService {
						// ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋กœ๋“œ
	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

  • ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์–ด๋””์—์„œ ๋กœ๋“œํ•˜๋Š”์ง€๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์–ด๋””์—์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋”ฐ๋ผ์„œ ๋‹ฌ๋ผ
  • ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๋กœ๋“œํ•˜๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋กœ๋“œํ•˜๋“  Spring Security๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” UserDetails๋กœ ๋ฆฌํ„ด ํ•ด์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค

SecurityContext์™€ SecurityContextHolder

SecurityContext๋Š” ์ธ์ฆ๋œ Authentication ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ด๊ณ , SecurityContextHolder๋Š” SecurityContext๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹น

  • SecurityContextHolder๋ฅผ ํ†ตํ•ด ์ธ์ฆ๋œ Authentication์„ SecurityContext์— ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ๋˜ํ•œ SecurityContextHolder๋ฅผ ํ†ตํ•ด ์ธ์ฆ๋œ Authentication ๊ฐ์ฒด์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธ
  • โญ Spring Security ์ž…์žฅ์—์„œ๋Š” SecurityContextHolder์— ์˜ํ•ด SecurityContext์— ๊ฐ’์ด ์ฑ„์›Œ์ ธ ์žˆ๋‹ค๋ฉด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๋กœ ๊ฐ„์ฃผ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SecurityContextHolder {
  ...
  ...

  private static SecurityContextHolderStrategy strategy;  
  // (1)  SecurityContextHolder์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต์„ ์˜๋ฏธํ•˜๋ฉฐ, 
  // SecurityContextHolder ๊ธฐ๋ณธ ์ „๋žต์€ ThreadLocalSecurityContextHolderStrategy
	// ์ด ์ „๋žต์€ ํ˜„์žฌ ์‹คํ–‰ ์Šค๋ ˆ๋“œ์— SecurityContext๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ThreadLocal์„ ์‚ฌ์šฉํ•˜๋Š” ์ „๋žต
  ...

  // (2) ํ˜„์žฌ ์‹คํ–‰ ์Šค๋ ˆ๋“œ์—์„œ SecurityContext๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค
	public static SecurityContext getContext() {
		return strategy.getContext();
	}
  ...

  // (3) ํ˜„์žฌ ์‹คํ–‰ ์Šค๋ ˆ๋“œ์— SecurityContext๋ฅผ ์—ฐ๊ฒฐ
  // setContext()๋Š” ๋Œ€๋ถ€๋ถ„ ์ธ์ฆ๋œ Authentication์„ ํฌํ•จํ•œ SecurityContext๋ฅผ ํ˜„์žฌ ์‹คํ–‰ ์Šค๋ ˆ๋“œ์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ
	public static void setContext(SecurityContext context) {
		strategy.setContext(context);
	}
  ...
}




Spring Security์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ ํ๋ฆ„

  • (1)์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด Spring Security๊ฐ€ ์ ์šฉ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— Username(๋กœ๊ทธ์ธ ID)๊ณผ Password๋ฅผ ํฌํ•จํ•œ request๊ฐ€ ์ „์†ก๋œ๋‹ค.
  • ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์š”์ฒญ์ด Spring Security์˜ Filter Chain๊นŒ์ง€ ๋“ค์–ด์˜ค๋ฉด ์—ฌ๋Ÿฌ Filter๋“ค ์ค‘์—์„œ UsernamePasswordAuthenticationFilter๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
    • ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” Spring Security Filter๋Š” UsernamePasswordAuthenticationFilter ์ด๋‹ค.
  • spring Security์—์„œ์˜ ์‹ค์งˆ์ ์ธ ์ธ์ฆ ์ฒ˜๋ฆฌ๋Š” ์ง€๊ธˆ๋ถ€ํ„ฐ ์‹œ์ž‘
  • ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์ „๋‹ฌ๋ฐ›์€ UsernamePasswordAuthenticationFilter๋Š” Username๊ณผ Password๋ฅผ ์ด์šฉํ•ด (2)์™€ ๊ฐ™์ด UsernamePasswordAuthenticationToken์„ ์ƒ์„ฑ
    • UsernamePasswordAuthenticationToken์€ Authentication ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„ ํด๋ž˜์Šค์ด๋ฉฐ, ์—ฌ๊ธฐ์—์„œ Authentication์€ โญ ์•„์ง ์ธ์ฆ์ด ๋˜์ง€ ์•Š์€ Authentication์ด๋‹ค.
  • ์•„์ง ์ธ์ฆ๋˜์ง€ ์•Š์€ Authentication์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” UsernamePasswordAuthenticationFilter๋Š” (3)๊ณผ ๊ฐ™์ด ํ•ด๋‹น Authentication์„ AuthenticationManager์—๊ฒŒ ์ „๋‹ฌ
  • AuthenticationManager๋Š” ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์ด๊ด„ํ•˜๋Š” ๋งค๋‹ˆ์ € ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ , AuthenticationManager๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋กœ ProviderManager ์ด๋‹ค. ์ฆ‰, `ProviderManager๊ฐ€ ์ธ์ฆ์ด๋ผ๋Š” ์ž‘์—…์„ ์ด๊ด„ํ•˜๋Š” ์‹ค์งˆ์ ์ธ ๋งค๋‹ˆ์ €์ธ ๊ฒƒ
  • (4)์™€ ๊ฐ™์ด ProviderManager๋กœ๋ถ€ํ„ฐ Authentication์„ ์ „๋‹ฌ๋ฐ›์€ AuthenticationProvider๋Š” (5)์™€ ๊ฐ™์ด UserDetailsService๋ฅผ ์ด์šฉํ•ด UserDetails๋ฅผ ์กฐํšŒ
    • UserDetails๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ์˜ ์ €์žฅ์†Œ์— ์ €์žฅ๋œ ์‚ฌ์šฉ์ž์˜ Username๊ณผ ์‚ฌ์šฉ์ž์˜ ์ž๊ฒฉ์„ ์ฆ๋ช…ํ•ด ์ฃผ๋Š” ํฌ๋ฆฌ๋ด์…œ(Credential)์ธ Password, ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ
  • UserDetailsService๋Š” (5)์—์„œ ์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ์˜ ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉ์ž์˜ ํฌ๋ฆฌ๋ด์…œ(Credential)์„ ํฌํ•จํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์กฐํšŒ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋“ฑ์˜ ์ €์žฅ์†Œ์—์„œ ์กฐํšŒํ•œ ์‚ฌ์šฉ์ž์˜ ํฌ๋ฆฌ๋ด์…œ(Credential)์„ ํฌํ•จํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ (7)๊ณผ ๊ฐ™์ด UserDetails๋ฅผ ์ƒ์„ฑํ•œ ํ›„, ์ƒ์„ฑ๋œ UserDetails๋ฅผ ๋‹ค์‹œ AuthenticationProvider์—๊ฒŒ ์ „๋‹ฌ
  • UserDetails๋ฅผ ์ „๋‹ฌ๋ฐ›์€ AuthenticationProvider๋Š” PasswordEncoder๋ฅผ ์ด์šฉํ•ด UserDetails์— ํฌํ•จ๋œ ์•”ํ˜ธํ™”๋œ Password์™€ ์ธ์ฆ์„ ์œ„ํ•œ Authentication์•ˆ์— ํฌํ•จ๋œ Password๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์ฆ
    • ๊ฒ€์ฆ์— ์„ฑ๊ณต(9) โ†’ ์ธ์ฆ๋œ Authentication์„ ์ƒ์„ฑ (UserDetails๋ฅผ ํ†ตํ•ด).
    • ์‹คํŒจ โ†’ Exception์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์ธ์ฆ ์ฒ˜๋ฆฌ๋ฅผ ์ค‘๋‹จ
  • AuthenticationProvider๋Š” ์ธ์ฆ๋œ Authentication์„ ProviderManager์—๊ฒŒ ์ „๋‹ฌ(10).
    • (2)์—์„œ์˜ Authentication์€ ์ธ์ฆ์„ ์œ„ํ•ด ํ•„์š”ํ•œ ์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ •๋ณด
    • ProviderManager์—๊ฒŒ ์ „๋‹ฌํ•œ Authentication์€ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด
  • Authentication์„ ์ „๋‹ฌ๋ฐ›์€ UsernamePasswordAuthenticationFilter๋Š” ๋งˆ์ง€๋ง‰์œผ๋กœ (12)์™€ ๊ฐ™์ด SecurityContextHolder๋ฅผ ์ด์šฉํ•ด SecurityContext์— ์ธ์ฆ๋œ Authentication์„ ์ €์žฅ
  • โญ ๊ทธ๋ฆฌ๊ณ  SecurityContext๋Š” ์ดํ›„์— Spring Security์˜ ์„ธ์…˜ ์ •์ฑ…์— ๋”ฐ๋ผ์„œ HttpSession์— ์ €์žฅ๋˜์–ด ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ๋„ ํ•˜๊ณ , HttpSession์„ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ฌด์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.


Spring Security์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ณด๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization) ์ฒ˜๋ฆฌ ํ๋ฆ„

์•„๋ž˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ์ธ์ฆ์— ์„ฑ๊ณตํ•œ ์ดํ›„, Spring Security์—์„œ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์–ด๋–ป๊ฒŒ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋Š”์ง€ ๊ทธ ์ฒ˜๋ฆฌ ํ๋ฆ„์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ทธ๋ฆผ์ด๋‹ค.

  • Spring Security Filter Chain์—์„œ URL์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์•ก์„ธ์Šค๋ฅผ ์ œํ•œํ•˜๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ Filter๋Š” ๋ฐ”๋กœ AuthorizationFilter ์ด๋‹ค.
  • AuthorizationFilter๋Š” ๋จผ์ € (1)๊ณผ ๊ฐ™์ด SecurityContextHolder๋กœ๋ถ€ํ„ฐ Authentication์„ ํš๋“ํ•œ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  (2)์™€ ๊ฐ™์ด SecurityContextHolder๋กœ๋ถ€ํ„ฐ ํš๋“ํ•œ Authentication๊ณผ HttpServletRequest๋ฅผ AuthorizationManager์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.
  • AuthorizationManager๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ด๊ด„ํ•˜๋Š” ๋งค๋‹ˆ์ € ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ , RequestMatcherDelegatingAuthorizationManager๋Š” AuthorizationManager๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

    RequestMatcherDelegatingAuthorizationManager๋Š” RequestMatcher ํ‰๊ฐ€์‹์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด๋‹น ํ‰๊ฐ€์‹์— ๋งค์น˜๋˜๋Š” AuthorizationManager์—๊ฒŒ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค

    โญ RequestMatcherDelegatingAuthorizationManager๊ฐ€ ์ง์ ‘ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ RequestMatcher๋ฅผ ํ†ตํ•ด ๋งค์น˜๋˜๋Š” AuthorizationManager ๊ตฌํ˜„ ํด๋ž˜์Šค์—๊ฒŒ ์œ„์ž„๋งŒ ํ•œ๋‹ค

  • RequestMatcherDelegatingAuthorizationManager ๋‚ด๋ถ€์—์„œ ๋งค์น˜๋˜๋Š” AuthorizationManager ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น AuthorizationManager ๊ตฌํ˜„ ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์„ ์ฒดํฌํ•œ๋‹ค(3).
  • ์ ์ ˆํ•œ ๊ถŒํ•œ์ด๋ผ๋ฉด (4)์™€ ๊ฐ™์ด ๋‹ค์Œ ์š”์ฒญ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ณ„์† ์ด์–ด๊ฐ„๋‹ค
  • ๋งŒ์•ฝ ์ ์ ˆํ•œ ๊ถŒํ•œ์ด ์•„๋‹ˆ๋ผ๋ฉด (5)์™€ ๊ฐ™์ด AccessDeniedException์ด throw๋˜๊ณ  ExceptionTranslationFilter๊ฐ€ AccessDeniedException์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค.



Spring Security์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ์ปดํฌ๋„ŒํŠธ

AuthorizationFilter

AuthorizationFilter๋Š” URL์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ์•ก์„ธ์Šค๋ฅผ ์ œํ•œํ•˜๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ Filter์ด๋ฉฐ, Spring Security 5.5 ๋ฒ„์ „๋ถ€ํ„ฐ FilterSecurityInterceptor๋ฅผ ๋Œ€์ฒดํ•œ๋‹ค.

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
29
30
31
32
33
34
35
36
public class AuthorizationFilter extends OncePerRequestFilter {

	private final AuthorizationManager<HttpServletRequest> authorizationManager;

  ...
  ...

  // (1)
	   //AuthorizationFilter ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, AuthorizationManager๋ฅผ DI ๋ฐ›๋Š”๋‹ค
	   //DI ๋ฐ›์€ AuthorizationManager๋ฅผ ํ†ตํ•ด ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ง„ํ–‰
	public AuthorizationFilter(AuthorizationManager<HttpServletRequest> authorizationManager) {
		Assert.notNull(authorizationManager, "authorizationManager cannot be null");
		this.authorizationManager = authorizationManager;
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request); 
		// (2)  DI ๋ฐ›์€ AuthorizationManager์˜ check() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ ์ ˆํ•œ ๊ถŒํ•œ ๋ถ€์—ฌ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌ
		// URL ๊ธฐ๋ฐ˜์œผ๋กœ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” **AuthorizationFilter**๋Š” AuthorizationManager์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋กœ 
		// RequestMatcherDelegatingAuthorizationManager๋ฅผ ์‚ฌ์šฉ
		
		this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
		if (decision != null && !decision.isGranted()) {
			throw new AccessDeniedException("Access Denied");
		}
		filterChain.doFilter(request, response);
	}

  ...
  ...

}

AuthorizationManager

์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ด๊ด„ํ•˜๋Š” ๋งค๋‹ˆ์ € ์—ญํ• ์„ ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค

1
2
3
4
5
6
7
8
9
10
11
12
@FunctionalInterface
public interface AuthorizationManager<T> {
  ...
  ...

	@Nullable
	AuthorizationDecision check(Supplier<Authentication> authentication, T object);
	 
	 // AuthorizationManager ์ธํ„ฐํŽ˜์ด์Šค๋Š” check() ๋ฉ”์„œ๋“œ ํ•˜๋‚˜๋งŒ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, 
	 // Supplier<Authentication>์™€ ์ œ๋„ˆ๋ฆญ ํƒ€์ž…์˜ ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ€์ง	
}

RequestMatcherDelegatingAuthorizationManager

RequestMatcherDelegatingAuthorizationManager๋Š” AuthorizationManager์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, ์ง์ ‘ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ  RequestMatcher๋ฅผ ํ†ตํ•ด ๋งค์น˜๋˜๋Š” AuthorizationManager ๊ตฌํ˜„ ํด๋ž˜์Šค์—๊ฒŒ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•œ๋‹ค.

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
29
30
31
32
33
public final class RequestMatcherDelegatingAuthorizationManager implements AuthorizationManager<HttpServletRequest> {

  ...
  ...

	@Override
	public AuthorizationDecision check(Supplier<Authentication> authentication, HttpServletRequest request) {
		if (this.logger.isTraceEnabled()) {
			this.logger.trace(LogMessage.format("Authorizing %s", request));
		}

    // (1) check() ๋ฉ”์„œ๋“œ์˜ ๋‚ด๋ถ€์—์„œ (1)๊ณผ ๊ฐ™์ด ๋ฃจํ”„๋ฅผ ๋Œ๋ฉด์„œ RequestMatcherEntry ์ •๋ณด๋ฅผ ์–ป์€ ํ›„์—
    // (2)์™€ ๊ฐ™์ด RequestMatcher ๊ฐ์ฒด๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค
		for (RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>> mapping : this.mappings) {

			RequestMatcher matcher = mapping.getRequestMatcher(); // (2)
			MatchResult matchResult = matcher.matcher(request);
			if (matchResult.isMatch()) {   
					// (3)  MatchResult.isMatch()๊ฐ€ true์ด๋ฉด AuthorizationManager ๊ฐ์ฒด๋ฅผ ์–ป์€ ๋’ค, 
					// AuthorizationManager ๊ตฌํ˜„ ํด๋ž˜์Šค์—๊ฒŒ ๊ถŒํ•œ ๋ถ€์—ฌ ์ฒ˜๋ฆฌ๋ฅผ ์œ„์ž„ํ•œ๋‹ค.
				AuthorizationManager<RequestAuthorizationContext> manager = mapping.getEntry();
				if (this.logger.isTraceEnabled()) {
					this.logger.trace(LogMessage.format("Checking authorization on %s using %s", request, manager));
				}
				return manager.check(authentication,
						new RequestAuthorizationContext(request, matchResult.getVariables()));
			}
		}
		this.logger.trace("Abstaining since did not find matching RequestMatcher");
		return null;
	}
}

โญ ์—ฌ๊ธฐ์„œ์˜ RequestMatcher๋Š” SecurityConfiguration์—์„œ .antMatchers("/orders/**").hasRole("ADMIN") ์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ ์ฒด์ธ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค

Comment

๋„ˆ๋ฌด ์–ด๋ ค์›Œ์„œ ์ •๋ฆฌํ•˜๋Š”๋ฐ ํ•œ์ฐธ ๊ฑธ๋ ธ๋‹ค,, ๊ทผ๋ฐ๋„ ์ดํ•ด๊ฐ€ ์•ˆ๊ฐ€๋Š” ๊ฒƒ์€ ํ•จ์ •;; ์–ด์„œ ์ดํ•ดํ•ด์•ผํ•˜๋Š”๋ฐ ๋‹ต์ด์—†๋‹ค ์ •๋ง ใ… ใ… ใ… 

Spring ์นดํ…Œ๊ณ ๋ฆฌ ๋‚ด ๋‹ค๋ฅธ ๊ธ€ ๋ณด๋Ÿฌ๊ฐ€๊ธฐ

Leave a comment