๊ด€๋ฆฌ ๋ฉ”๋‰ด

JiYoung Dev ๐Ÿ–ฅ

Spring Security ์ ์šฉ๊ธฐ (6) Spring Security Authorization(HttpServletRequests) ๋ณธ๋ฌธ

Study/Java

Spring Security ์ ์šฉ๊ธฐ (6) Spring Security Authorization(HttpServletRequests)

Shinjio 2024. 5. 5. 19:57

2024.05.05 - [Study/Java] - Spring Security ์ ์šฉ๊ธฐ (5) Spring Security Authentication ๋™์ž‘์›๋ฆฌ

 

Spring Security ์ ์šฉ๊ธฐ (5) Spring Security Authentication ๋™์ž‘์›๋ฆฌ

jwt์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•˜๊ณ  ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ ค๋˜ ์ค‘ spring security์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ์•„์ง ๋ถ€์กฑํ•˜๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์–ด๋–ป๊ฒŒ spring security๋Š” ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ , ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”๊ฐ€์—

danyoujeong.tistory.com

 

์ง€๋‚œ ์‹œ๊ฐ„์— ์ด์–ด ์ด๋ฒˆ์—๋Š” Spring Security์˜ Authorization ์ž‘๋™ ์›๋ฆฌ์™€ HttpRequest์— ๋Œ€ํ•œ ์ธ๊ฐ€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. 

์ด๋ฒˆ ํฌ์ŠคํŒ… ์—ญ์‹œ ์Šคํ”„๋ง ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์˜€๋‹ค.

https://docs.spring.io/spring-security/reference/servlet/authorization/index.html 

 

Authorization :: Spring Security

The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity. Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating w

docs.spring.io


๊ฐœ์š”

์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ๋ฐฉ๋ฒ•์„ ์„ค์ •ํ•œ ํ›„์—๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ๋Š” ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ์—์„œ ์ œ๊ณตํ•˜๋Š” ์ธ์ฆ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋“ ์ง€ ํ˜น์€ ๋‹ค๋ฅธ ์ธ์ฆ ๋ฐฉ๋ฒ•๊ณผ ํ†ตํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋“ ์ง€์™€๋Š” ๊ด€๊ณ„ ์—†์ด, ๊ถŒํ•œ ๋ถ€์—ฌ ์„œ๋น„์Šค๋ฅผ ์ผ๊ด€๋˜๊ณ  ๊ฐ„๋‹จํ•œ ๋ฐฉ์‹์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๊ถŒํ•œ ๊ทœ์น™ ๋ถ€์—ฌ๋Š” ์š”์ฒญ URI ๋ฐ ๋ฉ”์†Œ๋“œ์— ๊ทœ์น™์„ ๋ถ€์—ฌํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์•„๋ž˜์˜ ๋‚ด์šฉ์—์„œ ์š”์ฒญ URI์— ๋Œ€ํ•œ ๊ถŒํ•œ ๋ถ€์—ฌ ์ž‘์—… ๋ฐฉ์‹์— ๋Œ€ํ•ด ์ƒ์„ธํžˆ ๋‹ค๋ค„๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค. 


โš™๏ธAuthrization Architecture

Authorities

์ธ์ฆ(Authentication) ๊ณผ์ •์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ์ธ์ฆ ์ž๊ฒฉ ์ฆ๋ช…์„ ๊ฒ€์ฆํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋กœ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. 

์ด ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž ๊ฐ์ฒด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์ง€๋Š” ๊ถŒํ•œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ์ฒด๋“ค์„ "GrantedAuthority"๋ผ ํ•˜๋ฉฐ, ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ • ๋ฆฌ์†Œ์Šค ๋˜๋Š” ๊ธฐ๋Šฅ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. 

 

GrantedAuthority๋Š” AuthenticationManager์— ์˜ํ•ด Authentication ๊ฐ์ฒด์— ์‚ฝ์ž…๋˜๋ฉฐ,

๋‚˜์ค‘์— AccessDecisionManager๋Š” GrantedAuthority๋“ค์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ๋ฆฌ์†Œ์Šค๋‚˜ ๊ธฐ๋Šฅ์— ์—‘์„ธ์Šค ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. 

๋”ฐ๋ผ์„œ ์ด๋Ÿฌํ•œ GrantedAuthority๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ๋ถ€์—ฌ ๊ฒฐ์ •์„ ๋‚ด๋ฆด ๋•Œ ํ•„์ˆ˜์ ์ธ ์ •๋ณด์ด๋‹ค. 

 

GrantedAuthority ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋‹จ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. 

String getAuthority();

 

ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋Š” AuthorizationManger ์ธ์Šคํ„ด์Šค๊ฐ€ GrantedAuthority์˜ ์ •ํ™•ํ•œ ๋ฌธ์ž์—ด ํ‘œํ˜„์„ ์–ป๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. 

๋งŒ์•ฝ, GrantedAuthority๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ •ํ™•ํžˆ ํ‘œํ˜„๋  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ, GrantedAuthority๋Š” ๋ณต์žก(complex)ํ•˜๋‹ค๊ณ  ์—ฌ๊ฒจ์ง€๋ฉฐ getAuthority()๋Š” null์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. 

 

Spring Security๋Š” GrantedAuthority ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ SimpleGrantedAuthority ๊ตฌํ˜„์ฒด๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ๋‹ค. ์ด ๊ตฌํ˜„์ฒด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง€์ •ํ•œ ๋ฌธ์ž์—ด์„ GrantedAuthority๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ณด์•ˆ ์•„ํ‚คํ…์ฒ˜์™€ ํ•จ๊ป˜ ์ œ๊ณต๋˜๋Š” ๋ชจ๋“  AuthenticationProvider ์ธ์Šคํ„ด์Šค๋Š” SimpleGrantedAuthority๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Authentication ๊ฐ์ฒด๋ฅผ ์ฑ„์šด๋‹ค. 

 

๊ธฐ๋ณธ์ ์œผ๋กœ ์—ญํ•  ๊ธฐ๋ฐ˜์˜ ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™์€ ROLE_์„ ์ ‘๋‘์–ด๋กœ ์‚ฌ์šฉํ•œ๋‹ค. 

๋˜ํ•œ GrantedAuthorityDefaults๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

@Bean
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
	return new GrantedAuthorityDefaults("MYPREFIX_");
}

 

GrantedAuthorityDefaults๋ฅผ ์ •์  ๋ฉ”์„œ๋“œ๋กœ ๋…ธ์ถœํ•˜์—ฌ Spring์ด Spring Security์˜ ๋ฉ”์„œ๋“œ ๋ณด์•ˆ @Configuration ํด๋ž˜์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๊ธฐ ์ „์— ํ•ด๋‹น ๋นˆ์„ ๊ฒŒ์‹œํ•˜๋„๋ก ํ•œ๋‹ค. 


โš™๏ธInvocation Handling

Spring Security๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ์ด๋‚˜ ์›น ์š”์ฒญ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ๊ฐ์ฒด์— ๋Œ€ํ•œ ์—‘์„ธ์Šค๋ฅผ ์ œ์–ดํ•˜๋Š” ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. 

AuthorizationManager ์ธ์Šคํ„ด์Šค๋Š” ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ˜น์€ ์›น ์š”์ฒญ์ด ์ง„ํ–‰๋  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์‚ฌ์ „ ํ˜ธ์ถœ ๊ฒฐ์ •์„ ๋‚ด๋ฆฐ๋‹ค. 

์ฃผ์–ด์ง„ ๊ฐ’์ด ๋ฐ˜ํ™˜๋  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์‚ฌํ›„ ํ˜ธ์ถœ ๊ฒฐ์ • ๋˜ํ•œ AuthorizationManager์— ์˜ํ•ด์„œ ์ด๋ฃจ์–ด์ง„๋‹ค. 

 

The AuthorizationManager

AuthorizationManager๋Š” AccssDecisionManager์™€ AccessDecisionVoter๋ฅผ ๋Œ€์ฒดํ•œ๋‹ค. 

์ฆ‰ ์ด์ „์—๋Š” AccssDecisionManager ๋ฐ AccessDecisionVoter๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—‘์„ธ์Šค ๊ฒฐ์ •์„ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ, ์ด์ œ๋Š” AuthorizationManager๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๊ถŒ์žฅํ•œ๋‹ค. 

 

AuthorizationManager๋Š” Spring Security์˜ ์š”์ฒญ ๊ธฐ๋ฐ˜, ๋ฉ”์„œ๋“œ ๊ธฐ๋ฐ˜ ๋ฐ ๋ฉ”์‹œ์ง€ ๊ธฐ๋ฐ˜ ์ธ๊ฐ€ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ํ˜ธ์ถœ๋˜๋ฉฐ ์ตœ์ข… ์—‘์„ธ์Šค ์ œ์–ด ๊ฒฐ์ •์„ ๋‹ด๋‹นํ•œ๋‹ค. AuthorizationManager ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” ๋‘ ๊ฐœ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค. 

 

//์ธ๊ฐ€ ๊ฒฐ์ •์„ ๋‚ด๋ฆฌ๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ชจ๋“  ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ „๋‹ฌ ๋ฐ›๋Š”๋‹ค. 
//ํŠนํžˆ, ๋ณด์•ˆ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•จ์œผ๋กœ์จ ์‹ค์ œ ๋ณด์•ˆ ๊ฐ์ฒด ํ˜ธ์ถœ์— ํฌํ•จ๋œ ์ธ์ˆ˜๋ฅผ ๊ฒ€์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค. 
//์—‘์„ธ์Šค ํ—ˆ์šฉ -> ์–‘์ˆ˜์˜ AuthorizationDecision, ๊ฑฐ๋ถ€ -> ์Œ์ˆ˜์˜ AuthorizationDecision 
//๊ฒฐ์ •์„ ๋‚ด๋ฆฌ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ null AuthorizationDecision ๋ฐ˜ํ™˜
AuthorizationDecision check(Supplier<Authentication> authentication, Object secureObject);

//check๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  AuthorizaitonDecision์ด ์Œ์ˆ˜์ธ ๊ฒฝ์šฐ AccessDeniedException์„ throw
default AuthorizationDecision verify(Supplier<Authentication> authentication, Object secureObject)
        throws AccessDeniedException {
    // ...
}

 

Delegate ๊ธฐ๋ฐ˜์˜ AuthorizationManager ๊ตฌํ˜„

์‚ฌ์šฉ์ž๋“ค์€ ์ธ๊ฐ€(authorization)์˜ ๋ชจ๋“  ์ธก๋ฉด์„ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ AuthorizationManager๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, 

Spring Security๋Š ๊ฐœ๋ณ„ AuthorizationManager์™€ ํ˜‘๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ์œ„์ž„(delegate) ํ˜•์‹์˜ AuthorizationManager๋ฅผ ์ œ๊ณตํ•œ๋‹ค. 

 

์š”์ฒญ์— ๋Œ€ํ•œ ์ธ๊ฐ€๋ฅผ ์œ„ํ•ด์„œ๋Š” RequestMatcherDelegatingAuthorizationManager,

๋ฉ”์„œ๋“œ ๋ณด์•ˆ์˜ ๊ฒฝ์šฐ AuthorizationMangerBeforeMethodInterceptor์™€ AuthorizationManagerAfterMethodInterceptor๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

Authorization Manager Implementations

 

Hierarchical Roles

์–ด๋–ค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŠน์ • ์—ญํ• ์ด ๋‹ค๋ฅธ ์—ญํ• ์„ ์ž๋™์œผ๋กœ ํฌํ•จํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ผ๋ฐ˜์ ์ด๋‹ค. 

์˜ˆ๋ฅผ๋“ค์–ด ๊ด€๋ฆฌ์ž์™€ ์‚ฌ์šฉ์ž ์—ญํ• ์ด ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๋ฆฌ์ž๋Š” ์ผ๋ฐ˜ ์‚ฌ์šฉ์ž๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ์—ญํ•  ๊ณ„์ธต์„ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์—ญํ•  ํ˜น์€ ๊ถŒํ•œ์ด ๋‹ค๋ฅธ ์—ญํ• ์„ ํฌํ•จํ•ด์•ผ ํ•˜๋Š”์ง€๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

Spring Security์˜ RoleVoter์˜ ํ™•์žฅ๋œ ๋ฒ„์ „์ธ RoleHierarchyVoter RoleHierarchy๋กœ ๊ตฌ์„ฑ๋˜๋ฉฐ, ์‚ฌ์šฉ์ž์—๊ฒŒ ํ• ๋‹น๋œ ๋ชจ๋“  ๋„๋‹ฌ ๊ฐ€๋Šฅํ•œ ๊ถŒํ•œ์„ ์–ป๋Š”๋‹ค. 

 

์ผ๋ฐ˜์ ์ธ ๊ตฌ์„ฑ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

@Bean
static RoleHierarchy roleHierarchy() {
    RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
    hierarchy.setHierarchy("ROLE_ADMIN > ROLE_STAFF\n" +
            "ROLE_STAFF > ROLE_USER\n" +
            "ROLE_USER > ROLE_GUEST");
    return hierarchy;
}

// and, if using method security also add
@Bean
static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
	DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
	expressionHandler.setRoleHierarchy(roleHierarchy);
	return expressionHandler;
}

 

์œ„์˜ ์ฝ”๋“œ์—์„œ๋Š” 4๊ฐ€์ง€ ์—ญํ• (ADMIN, STAFF, USER, GUEST)์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ">" ๊ธฐํ˜ธ๋Š” ํฌํ•จ์„ ์˜๋ฏธํ•œ๋‹ค. 

์—ญํ•  ๊ณ„์ธต์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ ‘๊ทผ ์ œ์–ด ๊ตฌ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋‹จ์ˆœํ™”ํ•˜๊ฑฐ๋‚˜, ์‚ฌ์šฉ์ž์—๊ฒŒ ํ• ๋‹นํ•ด์•ผ ํ•˜๋Š” ๊ถŒํ•œ ์ˆ˜๋ฅผ ์ค„์ด๋Š” ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. ๋” ๋ณต์žกํ•œ ์š”๊ตฌ์‚ฌํ•ญ์˜ ๊ฒฝ์šฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ํ•„์š”๋กœ ํ•˜๋Š” ํŠน์ • ์•ก์„ธ์Šค ๊ตฌ๋„ˆํ•œ๊ณผ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ• ๋‹น๋œ ์—ญํ•  ๊ฐ„์˜ ๋…ผ๋ฆฌ์  ๋งคํ•‘์„ ์ •์˜ํ•˜์—ฌ, ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋กœ๋“œํ•  ๋•Œ ์ด ๋‘˜ ์‚ฌ์ด๋ฅผ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๋‹จ RoleHierarchy ๋นˆ ๊ตฌ์„ฑ์€ ์•„์ง @EnableMethodSecurity๋กœ ์ด์ „๋˜์ง€ ์•Š์•˜๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์˜ˆ์ œ๋Š” AccessDecision Voter๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๋ฉ”์„œ๋“œ ๋ณด์•ˆ์— RoleHierarchy ์ง€์›์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, github.com/spring-projects/spring-security/issues/12783 ์ด์Šˆ๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ @EnableGlobalMethodSecurity๋ฅผ ๊ณ„์† ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. 

→ ํ˜„์žฌ๋Š” @EnableMethodSecurity์—์„œ RoleHierarchy๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ.

→ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Spring Seucirty ์„ค์ • ํด๋ž˜์Šค์— @EnableGlobalMethodSecurity ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด ๋ฉ”์„œ๋“œ ๋ณด์•ˆ์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Œ

 

@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {

     @Bean
     public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        // ์—ญํ•  ๊ณ„์ธต ๊ตฌ์„ฑ
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
        return roleHierarchy;
      }
    // ์ถ”๊ฐ€์ ์ธ ์„ค์ •
}

โš™๏ธAuthorize HttpServletRequests

 

Spring Security๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ ์ˆ˜์ค€์—์„œ ๊ถŒํ•œ์„ ๋ชจ๋ธ๋ง ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Spring Security๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด /admin ํ•˜์œ„์˜ ๋ชจ๋“  ํŽ˜์ด์ง€์—๋Š” ํ•˜๋‚˜์˜ ๊ถŒํ•œ์ด ํ•„์š”ํ•˜๊ณ , ๋‹ค๋ฅธ ๋ชจ๋“  ํŽ˜์ด์ง€์—๋Š” ๊ฐ„๋‹จํžˆ ์ด์ฆ๋งŒ ํ•„์š”ํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

๊ธฐ๋ณธ์ ์œผ๋กœ Spring Security๋Š” ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ์ด ํ•„์š”ํ•˜๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ HttpSecurity ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋งˆ๋‹ค ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™์„ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค. 

 

http
    .authorizeHttpRequests((authorize) -> authorize
        .anyRequest().authenticated()
    )

 

ํ•ด๋‹น ์ฝ”๋“œ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์ด๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ธ์ฆ์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ Spring Security์— ์•Œ๋ ค์ค€๋‹ค.

 

Authorize HttpServletRequest

 

๊ธฐ๋ณธ์ ์œผ๋กœ AuthorizationFilter๋Š” Spring Security ํ•„ํ„ฐ ์ฒด์ธ์—์„œ ๋งˆ์ง€๋ง‰์— ์œ„์น˜ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ ์ด์ „์— ์กด์žฌํ•˜๋Š” ์ธ์ฆ, ์•…์šฉ๋ฐฉ์ง€๋“ฑ์˜ ํ•„ํ„ฐ๋Š” ๊ถŒํ•œ์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. AuthorizationFilter ์ด์ „์— ์ž์ฒด ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ด๋„ ์ด ํ•„ํ„ฐ๋Š” ๊ถŒํ•œ์ด ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Spring MVC ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” ์ƒํ™ฉ์ด ๋‹ฌ๋ผ์ง„๋‹ค. DispatcherServlet์— ์˜ํ•ด ์‹คํ–‰๋˜๋ฏ€๋กœ ์ด๋Š” AuthorizationFilter ์ดํ›„์— ์‹คํ–‰๋˜๋ฉฐ, ์—”๋“œํฌ์ธํŠธ๊ฐ€ ํ—ˆ์šฉ๋˜๋ ค๋ฉด authorizeHttpRequests์— ํฌํ•จ๋˜์–ด์•ผ ํ•œ๋‹ค. 

 

๋‹ค์Œ์€ /endpoint๊ฐ€ USER ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์ตœ์ข… ์‚ฌ์šฉ์ž์— ์˜ํ•ด์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ์š”๊ตฌํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

@Bean
SecurityFilterChain web(HttpSecurity http) throws Exception {
	http
		.authorizeHttpRequests((authorize) -> authorize
			.requestMatchers("/endpoint").hasAuthority("USER")
			.anyRequest().authenticated()
		)
        // ...

	return http.build();
}

 

๋งŒ์•ฝ /endpoint๊ฐ€ ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์•„๋‹Œ /resource ๋””๋ ‰ํ„ฐ๋ฆฌ ์•„๋ž˜์˜ ๋ชจ๋“  ์—”๋“œํฌ์ธํŠธ๋ฅผ ๋งค์นญํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์š”์ฒญ์ด /resource ๋˜๋Š” ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์ธ ๊ฒฝ์šฐ USER ๊ถŒํ•œ์„ ์š”๊ตฌํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ธ์ฆ๋งŒ ํ•„์š”๋กœ ํ•œ๋‹ค๊ณ  ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. 

 

http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers("/resource/**").hasAuthority("USER")
        .anyRequest().authenticated()
    )

 

๋˜ํ•œ, ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฒฝ๋กœ์—์„œ ๊ฒฝ๋กœ ๊ฐ’์„ ์ถ”์ถœํ•  ์ˆ˜๋„ ์žˆ๋‹ค. 

 

http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers("/resource/{name}").access(new WebExpressionAuthorizationManager("#name == authentication.name"))
        .anyRequest().authenticated()
    )

 

์ •๊ทœํ‘œํ˜„์‹์„ ์ด์šฉํ•˜์—ฌ ๋งค์นญ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ด๋ฆ„์„ ํฌํ•จํ•˜๊ณ  ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ด๋ฆ„์ด ์•ŒํŒŒ๋ฒณ๊ณผ ์ˆซ์ž๋กœ๋งŒ ์ด๋ฃจ์–ด์ ธ์•ผ ํ•˜๋Š” ๊ทœ์น™์ด ์žˆ๋Š” ๊ฒฝ์šฐ RegexRequestMatcher๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ๊ทœ์น™์„ ์ค€์ˆ˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 

์•„๋ž˜์˜ ์ฝ”๋“œ๋Š” ์š”์ฒญ์ด /resouce/[A-Za-z0-9]+์™€ ์ผ์น˜ํ•˜๋ฉด USER ๊ถŒํ•œ์„ ์š”๊ตฌํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ๋ชจ๋“  ์š”์ฒญ์€ ๊ฑฐ๋ถ€ํ•œ๋‹ค๊ณ  ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. 

 

http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers(RegexRequestMatcher.regexMatcher("/resource/[A-Za-z0-9]+")).hasAuthority("USER")
        .anyRequest().denyAll()
    )

 

HTTP ๋ฉ”์„œ๋“œ๋ณ„๋กœ ๊ทœ์น™์„ ๋งค์นญํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์€ ๋ถ€์—ฌ๋œ ๊ถŒํ•œ ๊ธฐ์ค€์œผ๋กœ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•  ๋•Œ์ด๋‹ค. 

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋“  GET ์š”์ฒญ์ด ์ฝ๊ธฐ ๊ถŒํ•œ์„ ๊ฐ€์ ธ์•ผ ํ•˜๊ณ , ๋ชจ๋“  POST ์š”์ฒญ์ด ์“ฐ๊ธฐ ๊ถŒํ•œ์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

http
    .authorizeHttpRequests((authorize) -> authorize
        .requestMatchers(HttpMethod.GET).hasAuthority("read")
        .requestMatchers(HttpMethod.POST).hasAuthority("write")
        .anyRequest().denyAll()
    )

 

์œ„์˜ ๋‹ค์–‘ํ•œ ์˜ˆ์ œ์™€ ๊ฐ™์ด ์š”์ฒญ์ด ์ผ์น˜ํ•˜๋ฉด permitAll, denyAll, hasAuthority์™€ ๊ฐ™์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์ธ์ฆํ•  ์ˆ˜ ์žˆ๋‹ค. 

DSL์— ๋‚ด์žฅ๋œ ๊ถŒํ•œ ๋ถ€์—ฌ ๊ทœ์น™์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. 

 

permitAll : ์š”์ฒญ์— ๋Œ€ํ•œ ์ธ์ฆ์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ ๊ณต๊ฐœ ์—”๋“œํฌ์ธํŠธ. ์ด ๊ฒฝ์šฐ์—๋Š” ์„ธ์…˜์—์„œ ์ธ์ฆ์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๋‹ค. 
denyAll : ์–ด๋– ํ•œ ๊ฒฝ์šฐ์—๋„ ์š”์ฒญ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด ๊ฒฝ์šฐ์—๋„ ์„ธ์…˜์—์„œ ์ธ์ฆ์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๋‹ค. 
hasAuthority : ์ธ์ฆ์ด ์ฃผ์–ด์ง„ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š” GrantedAuthortiy๋ฅผ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. 
hasRole : ROLE_ ์ ‘๋‘์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ hasAuthority์˜ ๋‹จ์ถ•ํ‚ค์ด๋‹ค. 
hasAnyAuthority : ์ธ์ฆ์ด ์ฃผ์–ด์ง„ ๊ฐ’ ์ค‘ ํ•˜๋‚˜์™€ ์ผ์น˜ํ•˜๋Š” GrantedAuthority๋ฅผ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค. 
hasAnyRole : ROLE_ ์ ‘๋‘์‚ฌ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ hasAnyAuthority์˜ ๋‹จ์ถ•ํ‚ค์ด๋‹ค. 
access : ์‚ฌ์šฉ์ž ์ •์˜ AuthorizationManager๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ก์„ธ์Šค๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค.

 

 

Security Matchers๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HttpSecurity๋ฅผ ์ ์šฉํ•  ์š”์ฒญ์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. 

@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.securityMatcher("/api/**")                            
			.authorizeHttpRequests(authorize -> authorize
				.requestMatchers("/user/**").hasRole("USER")       
				.requestMatchers("/admin/**").hasRole("ADMIN")     
				.anyRequest().authenticated()                      
			)
			.formLogin(withDefaults());
		return http.build();
	}
}

 

์œ„์˜ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ /api/user, /api/admin๊ณผ ๊ฐ™์€ ๊ฒฝ๋กœ๋กœ ์š”์ฒญ์ด ๋“ค์–ด์˜จ ๊ฒฝ์šฐ์— authorizHttpRequest ์„ค์ •์ด ๋œ๋‹ค๋Š” ์˜๋ฏธ๋กœ, 

๋ณด์•ˆ ํ•„ํ„ฐ ์ฒด์ธ์— ๋Œ€ํ•œ ์„ค์ •์ด ์ ์šฉ๋˜๋Š” ์š”์ฒญ์„ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.