1. Spring Security ๊ฐ์
Spring Security๋ ์์ ๊ฐ์ด ์ธ์ฆ๋ถํฐ ํธ์์ฑ ์ ํธ๋ฆฌํฐ, ์น ๋ธ๋ผ์ฐ์ ์์ ์ ์ฉ ๊ฐ๋ฅํ ์ธ์ ๊ณ ์ , ํด๋ฆญ์ฌํน, ํฌ๋ก์ค ์ฌ์ดํธ ์์ฒญ ์์กฐ(CSRF) ๋ฑ์ ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ๋ณดํธํ๋ ๋ฉ์ปค๋์ฆ๊น์ง ํฌ๊ด์ ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, ์ด๋ฌํ ๊ธฐ๋ฅ์ ๋ชจ๋์ ์ถ๊ฐํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค.
Spring Security๋ฅผ ๋์ ํ๋ฉด ์ธ์ฆ,์ธ๊ฐ ๊ธฐ๋ฅ์ ํ์คํ ํ๊ณ ์๋ํํ ์ ์์ด ๊ฐ๋ฐ์๊ฐ ๋ณด์ ๊ด๋ จ ์ฝ๋๋ฅผ ์ง์ ์์ฑํ์ง ์๊ณ ๋ ๋์ ์์ค์ ๋ณด์ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
2. Spring Security ์ฃผ์ ์ํคํ ์ฒ
Spring ์์ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ์ ๋ชจ๋ HTTP ์์ฒญ์ Dispatcher Servlet์ด ๊ฐ์ฅ ๋จผ์ ์์ ํ๋ค. ์ด๋ ์์ ํ HTTP ์์ฒญ ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ์ ํ ์ปจํธ๋กค๋ฌ์ ์์ฒญ ์ฒ๋ฆฌ๋ฅผ ์์ํ๋ ์ญํ ์ ํ๋ค.
๋ํ, ์ด์ ํ๊ฒฝ์ ๋ฐ๋ผ ์๋ฒ๋ก ๋ค์ด์ค๋ ๋ชจ๋ ์์ฒญ์ ๋ํด ๊ณตํต์ ์ผ๋ก ์ ์ฉํด์ผ ํ ๋ถ๊ฐ ์์ ์ด ์์ ๋๋ DispatcherServlet ์ด์ ๋จ๊ณ์ ์์นํ Filter๊ฐ ์ด๋ฅผ ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
Filter๋ javax.servlet.Filter ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ํด๋์ค๋ก, HTTP ์์ฒญ์ด DispatcherServlet์ ๋๋ฌํ๊ธฐ ์ ์ ์์ฒญ๊ณผ ์๋ต์ ๊ฐ๋ก์ฑ๊ณ ๋ถ๊ฐ ์์ ์ ์ฒ๋ฆฌํ๋ ์ญํ ์ ์ํํ๋ค. ์ ๊ทธ๋ฆผ์ ๋ณด๋ฉด, DispatcherServlet์ Java Spring ์ปจํ ์ด๋์ ๊ฐ์ฅ ์์ ์์นํ์ง๋ง, Spring Security Filter๋ Java Spring ์ปจํ ์ด๋ ์์ ์์นํ๋ค.
๋ฐ๋ผ์ Filter ๋จ๊ณ์์ ์ธ์ฆ, ์ธ๊ฐ, ๋ก๊น ๋ฑ์ ์ํํ๋ฉด Java Spring ์ปจํ ์ด๋์ ๋๋ฌํ๊ธฐ ์ ์ ๋ณด์ ์ํ์ ์ฐจ๋จํ์ฌ ์์คํ ์์ ์ฑ์ ๋์ผ ์ ์๋ค.
Spring Security๋ ์๋์ ๊ฐ์ด Filter๋ฅผ ํ๋ฉฐ ์ฌ๋ฌ ๋ณด์ ๊ธฐ๋ฅ๋ค์ ์ํํ๊ฒ ๋๋ค.
์์ ๋งํ๋ฏ์ด Java Spring์ IoC ์ปจํ ์ด๋์๋ ๋ณ๊ฐ์ ์ปจํ ์ด๋์ด๊ธฐ ๋๋ฌธ์ Java Spring์์ ์ ์๋ Bean์ ์ฃผ์ ๋ฐ์ ์ฌ์ฉํ ์ ์๋ค.
์น ์ปจํ ์ด๋๋ DelegatingFilterProxy ํด๋์ค๋ฅผ ์ฌ์ฉํด์ Spring IoC ์ปจํ ์ด๋์ ์ ์๋ ํน์ Bean(SpringSecurityFilterChain)์๊ฒ ์์ํจ์ผ๋ก์จ, Java Spring์ DI์ ๊ด๋ฆฌ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค. ์ด๋ฅผ ํตํด ์น ์ปจํ ์ด๋์์ ์์ฑ๋ Filter๊ฐ ์ง์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋์ ํด๋น Bean์ด ์์ฒญ์ ์ฒ๋ฆฌํ๊ฒ ๋๋ค.
์ด๋ฌํ ํ๋ฆ์ ๊ทธ๋ฆผ์ผ๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํํํ ์ ์๋ค.
1. ์ฌ์ฉ์๊ฐ ์์ ์์ฒญ
2. Servlet Container์ ํํฐ๋ค์ด ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ๋๊ณ ๊ทธ ์ค DelegatingFilterProxy๊ฐ ์์ฒญ์ ๋ฐ๊ฒ ๋ ๊ฒฝ์ฐ ์์ ์ด ์์ฒญ๋ฐ์ ์์ฒญ๊ฐ์ฒด๋ฅผ delegate request๋ก ์์ฒญ ์์์ ํ๋ค.
3. ์์ฒญ ๊ฐ์ฒด๋ ํน์ ํ ํํฐ(springSecurityFilterChain) ์์ ๋ฐ๊ฒ ๋๋ค.
4. FilterChainProxy์์๋ ์์ ์ด ๊ฐ์ง ๊ฐ๊ฐ์ ํํฐ๋ค์ ์ฐจ๋ก๋๋ก ์ํํ๋ฉฐ ๋ณด์์ฒ๋ฆฌ๋ฅผ ์ํํ๋ค.
5. ๋ณด์์ฒ๋ฆฌ๊ฐ ์๋ฃ๋๋ฉด ์ต์ข ์์์ ์์ฒญ์ ์ ๋ฌํ์ฌ ๋ค์ ๋ก์ง์ด ์ํ๋๋ค.
3. ์ธ์ฆ ๊ฐ์ฒด ๊ด๋ฆฌ
Authentication ์ธ์ฆ๊ฐ์ฒด๋?
๋น์ ์ด ๋๊ตฌ์ธ์ง ์ฆ๋ช ํ๋ ๊ฒ ์ฌ์ฉ์์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ํ ํฐ ๊ฐ๋ ์ผ๋ก ์ฌ์ฉํ๋ค.
์ธ์ฆ ์ id์ password๋ฅผ ๋ด๊ณ ์ธ์ฆ ๊ฒ์ฆ์ ์ํด ์ ๋ฌ๋์ด ์ฌ์ฉ๋๋ค.
์ธ์ฆ ํ ์ต์ข ์ธ์ฆ ๊ฒฐ๊ณผ(user ๊ฐ์ฒด, ๊ถํ ์ ๋ณด)๋ฅผ ๋ด๊ณ SecurityContext ์ ์ ์ฅ๋์ด ์ ์ญ์ ์ผ๋ก ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋ค.
Authentication authentication =
SecurityContexHolder.getContext().getAuthentication();
Authentication ๊ฐ์ฒด์ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ๋ค.
1. principal: ์ฌ์ฉ์ ์์ด๋ ํน์ User๊ฐ์ฒด๋ฅผ ์ ์ฅ
2. credentials: ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ
3. authorities: ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ถํ ๋ชฉ๋ก
4. details: ์ธ์ฆ ๋ถ๊ฐ ์ ๋ณด
5. Authenticated: ์ธ์ฆ ์ฌ๋ถ(Bool)
1. ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ ์๋(username + password ์ ๋ ฅ ๋ฐ ์ ๋ฌ)
2. usernamePasswordAuthenticationFilter(์ธ์ฆํํฐ)๊ฐ ์์ฒญ์ ๋ณด๋ฅผ ๋ฐ์์ ์ ๋ณด ์ถ์ถ์ ํ์ฌ ์ธ์ฆ๊ฐ์ฒด (Authentication)์ ์์ฑํ๋ค.
3. AuthenticationManager๊ฐ ์ธ์ฆ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๊ณ ์ธ์ฆ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ค.
4. ์ธ์ฆ ์ฑ๊ณต ํ Authentication ์ธ์ฆ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ด๋ถ์ Principal, Credentials, Authorities, Authenticated ๋ค์ ์ฑ์๋ฃ๋๋ค.
5. SecurityContextHolder๊ฐ์ฒด ์์ SecurityContext์ ์ ์ฅํ๋ค. → ์ธ์ฆ๊ฐ์ฒด๋ฅผ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
์ฌ์ฉ์ ๋ณ Authentication ์ธ์ฆ ๊ฐ์ฒด๋ ์ด๋ป๊ฒ ๊ตฌ๋ถํ ์ ์์๊น??
SecurityContextHolder๋ผ๋ ์ ์ญ ๊ฐ์ฒด ์์ SecurityContext์ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋๋ฐ,
์ด SecurityContextHolder๋ ThreadLocal์ ์ ์ฅ๋๊ธฐ ๋๋ฌธ์ ๊ฐ๊ธฐ ๋ค๋ฅธ ์ฐ๋ ๋๋ณ๋ก ๋ค๋ฅธ SecurityContextHolder ์ธ์คํด์ค๋ฅผ ๊ฐ์ง๊ณ ์์ด์ ์ฌ์ฉ์ ๋ณ๋ก ๊ฐ๊ธฐ ๋ค๋ฅธ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง ์ ์๋ค.
4. ์ธ์ฆ ์ ์ฅ์
SecurityContext
Authentication ๊ฐ์ฒด๊ฐ ์ ์ฅ๋๋ ๋ณด๊ด์๋ก ํ์ ์ ์ธ์ ๋ ์ง Authentication ๊ฐ์ฒด๋ฅผ ๊บผ๋ด์ด ์ธ ์ ์๋๋ก ์ ๊ณต๋๋ ํด๋์ค์ด๋ค.
ThreadLocal์ ์ ์ฅ๋์ด ์๋ฌด ๊ณณ์์๋ ์ฐธ์กฐ๊ฐ ๊ฐ๋ฅํ๋๋ก ์ค๊ณ๋๊ณ , ๋ค๋ฅธ Thread๋ก ๋ถํฐ ์์ ํ๋ค.
SecurityContextHolder
SecurityContext ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๊ณ ๊ฐ์ธ๊ณ ์๋ wrapper ํด๋์ค
SecurityContext๊ฐ์ฒด๋ฅผ ๋ฐ๋ก ์ ์ฅํ๋ ๊ฒ์ ์๋๊ณ , ์ ์ฅ ๋ฐฉ์(3๊ฐ์ง MODE)์ ๋ฐ๋ผ ์ ์ฅ์ ํ๊ณ ์๋ค.
- MODE_THREADLOCAL: ์ค๋ ๋๋น SecurityContext๊ฐ์ฒด๋ฅผ ํ ๋น. default
- MODE_INHERITABLETHREADLOCAL: ๋ฉ์ธ ์ค๋ ๋์ ์์ ์ค๋ ๋์ ๊ดํ์ฌ ๋์ผํ SecurityContext๋ฅผ ์ ์ง → Parent, Child thread์์ ๋์ผํ SecurityContext๋ฅผ ๊ฐ์ง๋ค.
- MODE_GLOBAL: ์์ฉ ํ๋ก๊ทธ๋จ์์ ๋จ ํ๋์ SecurityContext๋ฅผ ์ ์ฅํ๋ค. → Memory์์ ๋จ ํ๋์ SecurityContext๋ฅผ ๊ฐ์ง๊ณ ์ฐธ์กฐํ๋ค.
5. ํผ(Form) ๊ธฐ๋ฐ ๋ก๊ทธ์ธ
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.formLogin(formLogin ->
formLogin
.loginPage("/login") // ๋ก๊ทธ์ธ ํ์ด์ง URL
.loginProcessingUrl("/loginProc") // ๋ก๊ทธ์ธ ์ฒ๋ฆฌ URL
.usernameParameter("userId") // ์ฌ์ฉ์ ์ด๋ฆ ํ๋ผ๋ฏธํฐ ์ด๋ฆ
.passwordParameter("userPw") // ๋น๋ฐ๋ฒํธ ํ๋ผ๋ฏธํฐ ์ด๋ฆ
.defaultSuccessUrl("/main") // ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ์ด๋ํ URL
.failureHandler(customAuthenticationFailureHandler) // ๋ก๊ทธ์ธ ์คํจ ์ ์ฒ๋ฆฌ
.permitAll() // ๋ชจ๋ ์ฌ์ฉ์์๊ฒ "/login" ํ์ด์ง์ ๋ํ ์ ๊ทผ ํ์ฉ
);
return http.build();
}
Spring Security๊ฐ ์ฌ์ฉํ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ์ง์ ํ๊ณ , loginProcessingUrl() ํจ์์ ์ง์ ๋ URL๋ก ๋ก๊ทธ์ธ ์์ฒญ์ด ์ ์ก๋๋ฉด Spring Security๊ฐ usernameParameter(), passwordParameter()์ ์ค์ ๋ ํ๋ผ๋ฏธํฐ ๊ฐ์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์กฐํํ๊ณ ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๋ค.
ํ๋ก์ฐ
1. ๋ก๊ทธ์ธ ์์ฒญ์ด ๋ค์ด์ค๋ฉด UsernamePasswordAuthenticationFilter๋ HttpServletRequest ์์ ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ๋ฅผ ์ถ์ถํ์ฌ UsernamePasswordAuthenticationToken ์ด๋ผ๋ ์ธ์ฆ ํ ํฐ์ ์์ฑ
2. ์์ฑ๋ ํ ํฐ์ AuthenticationManager์๊ฒ ์ ๋ฌ
3. AUthenticationManager๋ ์ ๋ฌ๋ฐ์ ํ ํฐ์ AuthenticationProvicer์๊ฒ ์ ๋ฌ
4. UserDetailsService๋ฅผ ํตํด ๋ก๊ทธ์ธ ์์ฒญ์์ ์ ๋ณด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋น๊ตํ ํ, ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์์ ๊ฒฝ์ฐ ์ด๋ฅผ AuthenticationProvicer์๊ฒ ๋ฐํ
5. AuthenticationProvicer๋ ์ ๋ฌ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด์์ ํจ์ค์๋ ์ ๋ณด๋ฅผ ์ถ์ถํ์ฌ, ํจ์ค์๋ ๋น๊ต. ์ผ์นํ ๊ฒฝ์ฐ ์ธ์ฆ ํ ํฐ์ ์์ฑํ์ฌ AuthenticationManager์๊ฒ ๋ฐํ
6. AuthenticationManager๋ ์ฌ์ฉ์ ์ธ์ฆ ๊ฐ์ฒด๋ฅผ SecurityContextHolder์ ์ ์ฅ
7, 8. ๊ฒฐ๊ณผ ์ฒ๋ฆฌ
6. JWT ๊ธฐ๋ฐ ๋ก๊ทธ์ธ
JWT ๋?
JWT๋ Header, Payload, Signature 3๊ฐ์ง ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
Header๋ ๋๊ฐ์ง ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์๋ช ์ ์ฌ์ฉํ ์ํธํ ์๊ณ ๋ฆฌ์ฆ ๊ด๋ จ ์ ๋ณด์ ํ ํฐ์ ์ ํ์ ์๋ฆฌ๋ ์ ๋ณด๊ฐ ๋ด๊ฒจ ์๋ค.
Payload๋ Claims๋ผ๋ ์ ๋ณด๋ค์ ๊ฐ์ง๊ณ ์๋ค. ํด๋ ์์ ์ฌ์ฉ์์ ๊ฐ์ ์ํฐํฐ๋ค์ด๋ ์ถ๊ฐ ์ ๋ณด๋ค์ ์ํ๋ฅผ ๋ปํ๋ค. ํด๋ ์์๋ Registered, Public, Private 3๊ฐ์ง๊ฐ ์๋ค.
- Registered ํด๋ ์์ ๋ฏธ๋ฆฌ ์ ์๋ ํด๋ ์ ์ธํธ์ด๋ค. JWT ๋ฐ๊ธ์, ํ ํฐ ์ ๋ชฉ, ํ ํฐ ๋ง๋ฃ ์๊ฐ, ํ ํฐ ํ์ฑ ๋ ์ง, ํ ํฐ ๋ฐ๊ธ ์๊ฐ, JWT ๊ณ ์ ์๋ณ์ ๋ฑ, ๋ค์ํ ์ ๋ณด๊ฐ ํฌํจ๋๋ ํด๋ ์์ด๋ค.
- Public ํด๋ ์์ ์ฌ์ฉ์๊ฐ ์ ์ํ ์ ์๋ ํด๋ ์์ด๋ค.์ฌ์ฉ์๊ฐ ์ง์ ์ ์ํ๊ธฐ ๋๋ฌธ์ ์ด ํด๋ ์์์ ์ถฉ๋์ด ๋ฐ์ํ ์๋ ์๋ค. ๋ฐ๋ผ์ Public ํด๋ ์์ ์ด๋ฆ์ ๋ณดํต URI๋ก ์ ์ํด์ผ ํ๋ค.
- Private ํด๋ ์๋ ์ฌ์ฉ์๊ฐ ์ ์ํ ์ ์๋ ํด๋ ์์ด๋ค. ํต์ ๋น์ฌ์ ๊ฐ์ ์ ๋ณด๋ฅผ ๊ณต์ ํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ํด๋ ์์ผ๋ก ๊ณต๊ฐ๋์ด๋ ์๊ด์๋ '์ฌ์ฉ์๋ฅผ ํน์ ํ ์ ์๋' ์ ๋ณด๋ฅผ ๋ด๋๋ค.
Signature๋ ํ ํฐ์ ํฌํจ๋ ์ ๋ณด๋ค์ด ํต์ ๊ณผ์ ์์ ๋ณ๊ฒฝ๋์ง ์์๋ค๋ ๊ฒ์ ๊ฒ์ฆํ๋ ๋ถ๋ถ์ด๋ค. Signature๋ Header์ Payload๋ฅผ Base64-URL๋ก ์ธ์ฝ๋ฉํ ๋ฌธ์์ด๋ค๊ณผ Secret Key๋ฅผ ํฌํจํด HMAC SHA256 ์ํธํ ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ์ํธํํ๋ค.
๋นจ๊ฐ์์ Header, ๋ณด๋ฝ์์ Payload, ํ๋์์ Signature์ด๋ค.
ํ๋ก์ฐ
JWT ํ ํฐ์ ์ฌ์ฉํ ์ธ์ฆ, ์ธ๊ฐ ํ๋ก์ธ์ค๋ ๋๋ต์ ์ผ๋ก ์๋์ ๊ฐ๋ค.
์ ํ๋ก์ธ์ค์ ํด๋นํ๋ ๋ก์ง์ ์๋์ ๊ฐ์ด ๊ตฌํ๋๋ค. ์ธ๋ถ์ ์ธ ์ฝ๋๋ค์ ์๋ตํ์ง๋ง, ํ๋ฆ์ ํ์ ํ๊ธฐ์ ์ถฉ๋ถํ ๊ฒ์ด๋ค.
@RequiredArgsConstructor
@Component
public class JwtFilter extends OncePerRequestFilter {
private final JwtProvier jwtProvider;
private final CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = extractToken(request);
if (token != null && jwtProvider.validateToken(token)) {
setAuthentication(token);
}
filterChain.doFilter(request, response);
}
private String extractToken(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.substring(7);
}
return null;
}
private void setAuthentication(String token) {
Long memberId = jwtProvider.getMemberId(token);
UserDetails userDetails = customUserDetailsService.loadUserByUsername(memberId.toString());
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null,
userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
(์ฐธ๊ณ ) ํ์ฌ ๋ก๊ทธ์ธํ ํ์ & RBAC ๊ด๋ฆฌ
๋ก๊ทธ์ธํ ํ์์ ๊ฐ์ ธ์ค๋ 3๊ฐ์ง ๋ฐฉ๋ฒ
1. SecurityUtils ์ฌ์ฉ
public class SecurityUtils {
public static LoginMember getLoginMember() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
LoginMember loginMember = (LoginMember) authentication.getPrincipal();
return loginMember;
}
return null;
}
}
2. @AuthenticationPrincipal ์ด๋ ธํ ์ด์ ์ฌ์ฉ
public class UserController {
@GetMapping("/current-user")
public String getCurrentUser(@AuthenticationPrincipal LoginMember loginMember) {
return userDetails.getUsername();
}
}
3. ArgumentResolver ๋ฑ๋ก
@AuthenticationPrincipal ์ด๋ ธํ ์ด์ ์ ๋๋ฌด ๊ธธ๋ค๋ฉด ArgumentResolver๋ฅผ ๋ณ๋๋ก ๋ฑ๋กํด์ ์ฌ์ฉํด๋ ์ข๋ค.
@Component
public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(LoginMember.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
@Configuration
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final LoginMemberArgumentResolver loginMemberArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginMemberArgumentResolver);
}
}
public class UserController {
@GetMapping("/current-user")
public String getCurrentUser(LoginMember loginMember) {
return userDetails.getUsername();
}
}
๋ญ ์ฌ์ฉํด๋ ์๊ด์์ง๋ง ๋ ๊ฐ์ธ์ ์ผ๋ก 3๋ฒ์ด ๊ฐ์ฅ ๋ง์ ๋ ๋ค.
RBAC์ ๊ด๋ฆฌํ๋ 2๊ฐ์ง ๋ฐฉ๋ฒ
1. http.authorizeHttpRequests()
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ... //
http.authorizeHttpRequests(authorize -> authorize
.antMatchers("/admin/**").hasRole("ADMIN") // ๊ด๋ฆฌ์๋ง ์ ๊ทผ ๊ฐ๋ฅ
.antMatchers("/manager/**").hasAnyRole("ADMIN", "MANAGER") // ๊ด๋ฆฌ์์ ๋งค๋์ ์ ๊ทผ ๊ฐ๋ฅ
.antMatchers("/user/**").hasRole("USER") // ์ฌ์ฉ์๋ง ์ ๊ทผ ๊ฐ๋ฅ
.antMatchers("/public/**").permitAll() // ๋ชจ๋ ์ฌ์ฉ์ ์ ๊ทผ ๊ฐ๋ฅ
.anyRequest().authenticated() // ๊ทธ ์ธ ์์ฒญ์ ์ธ์ฆ ํ์
);
return http.build();
}
2. ๋ฉ์๋ ๊ธฐ๋ฐ RBAC ์ค์
@Service
public class UserService {
@PreAuthorize("hasRole('ADMIN')") // ADMIN๋ง ์ ๊ทผ ๊ฐ๋ฅ
public void adminOnlyMethod() {
System.out.println("Admin only method");
}
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public void adminOrManagerMethod() {
System.out.println("Admin or Manager method");
}
@PreAuthorize("hasRole('USER')") // USER๋ง ์ ๊ทผ ๊ฐ๋ฅ
public void userOnlyMethod() {
System.out.println("User only method");
}
}
1๋ฒ์งธ ๋ฐฉ๋ฒ์ /* ๋ฅผ ์ฌ์ฉํด์ ํจํด์ผ๋ก ๊ด๋ฆฌํ๊ฒ ๋๋๋ฐ ํด๋จผ ์๋ฌ๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ๋ค. ๋ํ ํน์ ์๋ํฌ์ธํธ๋ฅผ ๋ณด๊ณ ํ์ํ ๊ถํ์ ์์๋ณด๊ธฐ ์ํด์ SecurityConfig์ ๋ค์ด๊ฐ ์ง์ ์ฐพ์๋ด์ผ ํ๋ค.
๊ทธ๋์ ๋๋ ๊ฐ์ธ์ ์ผ๋ก 2๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋ ์ ํธํ๊ณ ์๋์ ๊ฐ์ด custom annotaion์ ๋ง๋ค์ด ์ฌ์ฉํ๊ณ ์๋ค.