Search

λ©”μ„œλ“œ κΆŒν•œ 관리

λ©”μ„œλ“œ κΆŒν•œ 관리

μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° μ„€μ • ν΄λž˜μŠ€κ°€ μ•„λ‹Œ, 컨트둀러 μš”μ²­ λ©”μ†Œλ“œμ—μ„œ λ©”μ†Œλ“œ μˆ˜μ€€μ—μ„œμ˜ κΆŒν•œμ„ κ΄€λ¦¬ν•˜λŠ” 방법

μ μš©λ°©λ²•

β€’
μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° μ„€μ • 클래슀(SecurityConfig.java)
β—¦
@EnableMethodSecurity (spring boot 3.2~)
β—¦
@EnableGlobalMethodSecurity (spring boot ~3.2)
β€’
컨트둀러 λ©”μ†Œλ“œμ— κΆŒν•œ μ œμ–΄
β—¦
@Secured
β—¦
@PreAuthorize
β—¦
@PostAuthorize

μŠ€ν”„λ§ μ‹œνλ¦¬ν‹° μ„€μ • 클래슀(SecurityConfig.java)

β€’
@EnableMethodSecurity (spring boot 3.2~)
β€’
@EnableGlobalMethodSecurity (spring boot ~3.2)

@EnableMethodSecurity

spring boot 3.2 버전 λΆ€ν„°λŠ” @EnableGlobalMethodSecurity λŠ” depreacated
@EnableMethodSecurity ꢌμž₯
λ©”μ†Œλ“œ μˆ˜μ€€μ—μ„œμ˜ λ³΄μ•ˆ μ„€μ • κΈ°λŠ₯을 ν™œμ„±ν™”ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜

μ£Όμš” 속성

속성
μ„€λͺ…
μ‚¬μš© 예제
securedEnabled
@Secured μ–΄λ…Έν…Œμ΄μ…˜ ν™œμ„±ν™” - μ—­ν• (Role) 기반 μ ‘κ·Ό μ œμ–΄λ₯Ό κ°€λŠ₯ν•˜κ²Œ 함
@Secured("ROLE_ADMIN")
prePostEnabled
@PreAuthorize 및 @PostAuthorize μ–΄λ…Έν…Œμ΄μ…˜μ„ ν™œμ„±ν™” - ν‘œν˜„μ‹ 기반 μ œμ–΄λ₯Ό κ°€λŠ₯ν•˜κ²Œ 함
@PreAuthorize("hasRole('ADMIN')") @PostAuthorize("returnObject.username == authentication.name")

securedEnabled = true

μ—­ν• (Role; κΆŒν•œ) 기반으둜 κ°„λ‹¨ν•œ κΆŒν•œ μ œμ–΄
@Slf4j @Configuration @EnableWebSecurity @EnableMethodSecurity(securedEnabled = true) public class SecurityConfig {
Java
볡사
@Secured("ROLE_USER") @GetMapping("/path/to") public String getMethod() { }
Java
볡사
ROLE_USER, ROLE_ADMIN λ“±μ˜ κΆŒν•œμ„ 가진 μ‚¬μš©μž μš”μ²­λ§Œ μ²˜λ¦¬κ°€ λ˜λ„λ‘ ν•„ν„°λ§ν•˜κ²Œ λ©λ‹ˆλ‹€.

prePostEnabled = true

@Slf4j @Configuration @EnableWebSecurity @EnableMethodSecurity(prePostEnabled = true) public class SecurityConfig { }
Java
볡사
@PreAuthorize("hasRole('ADMIN')") @GetMapping("/path/to") public String getMethod() { }
Java
볡사

μ μš©λ˜λŠ” μ£Όμš” ν•„ν„°

β€’
MethodSecurityInterceptor
β—¦
λ©”μ†Œλ“œ λ³΄μ•ˆμ„ μ‹€μ œλ‘œ μˆ˜ν–‰ν•˜λŠ” 핡심 ν•„ν„°μž…λ‹ˆλ‹€.
β—¦
@Secured와 같은 μ–΄λ…Έν…Œμ΄μ…˜μ˜ κΆŒν•œ μ œμ–΄λ₯Ό μ²˜λ¦¬ν•˜λ©°, λ©”μ†Œλ“œ 호좜 전에 인증된 μ‚¬μš©μžμ˜ κΆŒν•œμ„ ν™•μΈν•©λ‹ˆλ‹€.
β€’
FilterSecurityInterceptor
β—¦
Spring Security의 HTTP μš”μ²­ λ³΄μ•ˆ ν•„ν„°λ‘œ, λ©”μ†Œλ“œ λ³΄μ•ˆλ³΄λ‹€λŠ” URL νŒ¨ν„΄ 기반의 μ ‘κ·Ό μ œμ–΄λ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.

@EnableGlobalMethodSecurity

spring boot 3.2 버전 λΆ€ν„°λŠ” @EnableGlobalMethodSecurity λŠ” depreacated
@EnableMethodSecurity ꢌμž₯
λ©”μ†Œλ“œ μˆ˜μ€€μ—μ„œμ˜ λ³΄μ•ˆ μ„€μ • κΈ°λŠ₯을 ν™œμ„±ν™”ν•˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜

컨트둀러 λ©”μ†Œλ“œμ— κΆŒν•œ μ œμ–΄

β€’
@Secured
β€’
@PreAuthorize
β€’
@PostAuthorized
μ–΄λ…Έν…Œμ΄μ…˜
적용 μ‹œμ 
μ£Όμš” νŠΉμ§•
@Secured
λ©”μ†Œλ“œ 호좜 μ „
- μ—­ν• (Role) 기반의 κ°„λ‹¨ν•œ λ³΄μ•ˆ. - ROLE_ 접두사 ν•„μš” - SpEL 미지원.
@PreAuthorize
λ©”μ†Œλ“œ 호좜 μ „
- SpEL을 μ‚¬μš©ν•œ ν‘œν˜„μ‹ 기반 λ³΄μ•ˆ. - 동적 κΆŒν•œ 검사 및 λ³΅μž‘ν•œ 쑰건 처리 κ°€λŠ₯.
@PostAuthorize
λ©”μ†Œλ“œ 호좜 ν›„
- λ°˜ν™˜κ°’μ„ 기반으둜 λ³΄μ•ˆ 검사. - SpEL 지원. - λ°˜ν™˜κ°’ 기반의 쑰건 처리 κ°€λŠ₯.

@Secured

λ‹¨μˆœν•œ μ—­ν• (Role) 기반 κΆŒν•œ 검사 - μš”μ²­ μ•ž λ‹¨μ—μ„œ κΆŒν•œμ œμ–΄
@Controller @RequestMapping("/board") public class BoardController { // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)λ₯Ό 가진 μ‚¬μš©μž μš”μ²­λ§Œ μ²˜λ¦¬ν•œλ‹€. @Secured("ROLE_USER") @GetMapping("/{id}") public String getBoard(@PathVariable("id") String id) { ... } }
Java
볡사

@PreAuthorize

λ‹¨μˆœ κΆŒν•œ 검사 및 SpEL(μŠ€ν”„λ§ ν‘œν˜„μ‹)을 기반으둜 λ³΅μž‘ν•œ 쑰건의 κΆŒν•œ 검사 - μš”μ²­ μ•ž λ‹¨μ—μ„œ κΆŒν•œμ œμ–΄
@Controller @RequestMapping("/board") public class BoardController { // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)λ₯Ό 가진 μ‚¬μš©μž μš”μ²­λ§Œ μ²˜λ¦¬ν•œλ‹€. @PreAuthorize("hasRole('USER')") // μ‚¬μš©μž κΆŒν•œ(ROLE_USER), κ΄€λ¦¬μž κΆŒν•œ(ROLE_ADMIN)λ₯Ό 가진 μ‚¬μš©μž μš”μ²­λ§Œ μ²˜λ¦¬ν•œλ‹€. // @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @GetMapping("/{id}") public String getBoard(@PathVariable("id") String id) { ... } }
Java
볡사

@PostAuthorized

λ‹¨μˆœ κΆŒν•œ 검사 및 SpEL(μŠ€ν”„λ§ ν‘œν˜„μ‹)을 기반으둜 λ³΅μž‘ν•œ 쑰건의 κΆŒν•œ 검사 - λ©”μ†Œλ“œ μ‹€ν–‰ ν›„ λ°˜ν™˜ 값에 λŒ€ν•œ κΆŒν•œ 검사
β€’
μš”μ²­ μžμ›(κ²Œμ‹œκΈ€)에 λŒ€ν•΄μ„œ μž‘μ„±μžλ§Œ μ‘°νšŒκ°€ κ°€λŠ₯ν•œ 경우
@RestController @RequestMapping("/board") public class BoardController { @Autowried BoardService boardService; // λ°˜ν™˜λœ κ²Œμ‹œκΈ€ 객체의 userNo 와 인증된 μ‚¬μš©μžμ˜ User.no κ°€ μΌμΉ˜ν•˜λŠ”μ§€ 확인 @PostAuthorize("returnObject.userNo == authentication.principal.user.no") @GetMapping("/{id}") public Board getBoard(@PathVariable("id") String id) { Board board = boardService.select(id); String userNo = board.getUserNo(); return board; } }
Java
볡사
β€’
응닡 κ²°κ³Ό
β—¦
μž‘μ„±μž 본인인 경우, μš”μ²­ν•œ κ²Œμ‹œκΈ€ 정보가 응닡
β—¦
μž‘μ„±μž 본인이 μ•„λ‹Œ 경우, 403 Forbidden μ—λŸ¬ 응닡
β€’
returnObject
β—¦
μš”μ²­ 컨트둀러 λ©”μ†Œλ“œμ—μ„œ λ°˜ν™˜ν•˜λŠ” 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” ν‚€μ›Œλ“œ
β—¦
μ—¬κΈ°μ„œλŠ”, return board; Board νƒ€μž…μ˜ κ²Œμ‹œκΈ€ 정보 객체λ₯Ό 가리킨닀.

SpEL( Spring Expression Language ) κΆŒν•œ μ œμ–΄ ν•¨μˆ˜

ν•¨μˆ˜
μ„€λͺ…
μ‚¬μš© μ˜ˆμ‹œ
hasRole('role')
μ‚¬μš©μž κΆŒν•œμ΄ μ§€μ •λœ μ—­ν• (role)인지 확인. ROLE_ 접두사 μƒλž΅κ°€λŠ₯ ROLE_ 접두사가 μžλ™μœΌλ‘œ λΆ™μŒ
@PreAuthorize("hasRole('ADMIN')")
hasAuthority('authority')
μ‚¬μš©μž κΆŒν•œμ΄ μ§€μ •λœ κΆŒν•œ(authority)인지 확인. ROLE_ 접두사 포함
@PreAuthorize("hasAuthority('ROLE_USER')")
isAuthenticated()
μ‚¬μš©μžκ°€ 인증된 μƒνƒœμΈμ§€ 확인. (둜그인 μ—¬λΆ€)
@PreAuthorize("isAuthenticated()")
isAnonymous()
μ‚¬μš©μžκ°€ 읡λͺ…(비인증) μƒνƒœμΈμ§€ 확인.
@PreAuthorize("isAnonymous()")
permitAll()
λͺ¨λ“  μ‚¬μš©μžκ°€ μ ‘κ·Όν•  수 μžˆλ„λ‘ ν—ˆμš©.
@PreAuthorize("permitAll()")
denyAll()
λͺ¨λ“  μ‚¬μš©μžμ˜ 접근을 κ±°λΆ€.
@PreAuthorize("denyAll()")
hasPermission(target, permission)
νŠΉμ • λŒ€μƒμ— λŒ€ν•΄ νŠΉμ • κΆŒν•œ(permission)을 가지고 μžˆλŠ”μ§€ 확인.
@PreAuthorize("hasPermission(#post, 'EDIT')")
principal
ν˜„μž¬ 인증된 μ‚¬μš©μžμ˜ principal을 μ°Έμ‘°.
@PreAuthorize("principal.username == 'admin'")

κΆŒν•œ μ œμ–΄ μ˜ˆμ‹œ

β€’
μ†Œμœ μž 검증 둜직
β€’
κ²Œμ‹œκΈ€ 등둝
β€’
κ²Œμ‹œκΈ€ 쑰회
β€’
κ²Œμ‹œκΈ€ μˆ˜μ •
β€’
κ²Œμ‹œκΈ€ μ‚­μ œ

μ†Œμœ μž 검증 둜직

public interface BoardService { ... // μ†Œμœ μž 확인 public boolean isOwner(String id, Long userNo) throws Exception; ... }
Java
볡사
@Slf4j @Service("BoardService") // ⭐ 빈 이름을 BoardService 둜 지정 public class BoardServiceImpl implements BoardService { ... /** * @param id : κ²Œμ‹œκΈ€ id, userNo : νšŒμ› no (PK) * κ²Œμ‹œκΈ€ id둜 μž‘μ„±μž userNo λ₯Ό μ‘°νšŒν•˜μ—¬, * 인증된 μ‚¬μš©μž no 와 μΌμΉ˜ν•˜λŠ”μ§€ 확인 */ @Override public boolean isOwner(String id, Long userNo) throws Exception { log.info("isOwner - id : " + id); log.info("isOwner - userNo : " + userNo); Board board = select(id); Long boardUserNo = board.getUserNo(); if( userNo != null && userNo == boardUserNo ) { return true; } return false; } }
Java
볡사

κ²Œμ‹œκΈ€ 등둝

인증된 μ‚¬μš©μž, 즉 νšŒμ›λ§Œ κ²Œμ‹œκΈ€μ„ 등둝할 수 μžˆλ‹€.
@Controller @RequestMapping("/board") public class BoardController { // κ²Œμ‹œκΈ€ 등둝 ν™”λ©΄ @Secured("ROLE_USER") // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)인 경우 //@PreAuthorize("hasRole('USER')") // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)인 경우 //@PreAuthorize("isAuthenticated()") // 인증된 μ‚¬μš©μž 인 경우 //@PreAuthorize("isAuthenticated() and hasRole('ADMIN')") // 인증 + κ΄€λ¦¬μžμΈ 경우 @GetMapping("/insert") public String insert() { ... } // κ²Œμ‹œκΈ€ 등둝 처리 @Secured("ROLE_USER") // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)인 경우 //@PreAuthorize("hasRole('USER')") // μ‚¬μš©μž κΆŒν•œ(ROLE_USER)인 경우 //@PreAuthorize("isAuthenticated()") // 인증된 μ‚¬μš©μž 인 경우 //@PreAuthorize("isAuthenticated() and hasRole('ADMIN')") // 인증 + κ΄€λ¦¬μžμΈ 경우 @PostMapping("") public String insertPost(Board board) { ... } }
Java
볡사

κ²Œμ‹œκΈ€ 쑰회

λˆ„κ΅¬λ‚˜ κ²Œμ‹œκΈ€μ„ μ‘°νšŒν•  수 μžˆλ‹€.
@Controller @RequestMapping("/board") public class BoardController { // λ³„λ„λ‘œ κΆŒν•œμ œμ–΄ μ•ˆ 함 @GetMapping("/{id}") public String select(@PathVariable("id") String id) { ... return "/board/select"; } }
Java
볡사

κ²Œμ‹œκΈ€ μˆ˜μ •

μž‘μ„±μž 본인 λ˜λŠ” κ΄€λ¦¬λ§Œ κ²Œμ‹œκΈ€ μˆ˜μ •μ΄ κ°€λŠ₯ν•˜λ‹€.
@Controller @RequestMapping("/board") public class BoardController { @Autowried BoardService boardService; // μˆ˜μ • ν™”λ©΄ // πŸ‘©β€πŸ’Ό μž‘μ„±μž 본인 πŸ‘©β€πŸ”§ κ΄€λ¦¬μž @PreAuthorize(" hasRole('ADMIN') or (#p0 != null and @BoardService.isOwner(#p0, authentication.principal.user.no) )") @GetMapping("/update/{id}") public String update(@PathVariable("id") String id) { Board board = boardService.select(id); ... } // μˆ˜μ • 처리 // πŸ‘©β€πŸ’Ό μž‘μ„±μž 본인 πŸ‘©β€πŸ”§ κ΄€λ¦¬μž @PreAuthorize(" hasRole('ADMIN') or (#p0.id != null and @BoardService.isOwner(#p0.id, authentication.principal.user.no) )") @ResponseBody @PutMapping("") public String update(@RequestBody Board board) { Board board = boardService.update(board); ... return "SUCCESS"; } }
Java
볡사
@PreAuthorize μ–΄λ…Έν…Œμ΄μ…˜ μ•ˆμ—μ„œ, SpEL ν‘œν˜„μ‹μ„ μ‚¬μš©ν•˜λ©΄, #p0, #p1… 와 같은 ν˜•μ‹μœΌλ‘œ νŒŒλΌλ―Έν„°λ₯Ό 인덱슀둜 μ§€μ •ν•˜μ—¬, κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
public String update(@PathVariable("id") String id) { ...
Java
볡사
μ—¬κΈ°μ„œ 첫번째 (인덱슀 0 ) νŒŒλΌλ―Έν„°λ₯Ό κ°€μ Έμ˜€λ €λ©΄, SpEL ν‘œν˜„μ‹μ—μ„œλŠ” #p0 으둜 μ§€μ •ν•΄μ„œ κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€,
νŒŒλΌλ―Έν„° - @PathVariable("id") String id
SpEL - #p0
id #p0
@BoardService.isOwner(#p0.id, authentication.principal.user.no)
Java
볡사
SpEL ν‘œν˜„μ‹ μ•ˆμ—μ„œ, "@λΉˆμ΄λ¦„.λ©”μ†Œλ“œ" ν˜•νƒœλ‘œ νŠΉμ • 빈의 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.
μ—¬κΈ°μ—μ„œλŠ” λ©”μ†Œλ“œμ— νŒŒλΌλ―Έν„° id(κ²Œμ‹œκΈ€ id), 인증된 μ‚¬μš©μž no λ₯Ό λ©”μ†Œλ“œλ‘œ μ „λ‹¬ν•˜μ—¬ μ†Œμœ μžμΈμ§€ κ²€μ¦ν•˜κ³  μ—¬λΆ€λ₯Ό true, false 둜 λ°˜ν™˜λ°›μ•„ μ†Œμœ μžλ₯Ό λ©”μ†Œλ“œ 호좜 전에 κΆŒν•œ μ œμ–΄ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

κ²Œμ‹œκΈ€ μ‚­μ œ

μž‘μ„±μž 본인 λ˜λŠ” κ΄€λ¦¬λ§Œ κ²Œμ‹œκΈ€ μ‚­μ œκ°€ κ°€λŠ₯ν•˜λ‹€.
@Controller @RequestMapping("/board") public class BoardController { @Autowried BoardService boardService; // μ‚­μ œ 처리 // πŸ‘©β€πŸ’Ό μž‘μ„±μž 본인 πŸ‘©β€πŸ”§ κ΄€λ¦¬μž @PreAuthorize("( hasRole('ADMIN')) or (#p0 != null and @BoardService.isOwner(#p0, authentication.principal.user.no))") @ResponseBody @DeleteMapping("/{id}") public String update(@PathVariable("id") String id) { Board board = boardService.delete(id); ... return "SUCCESS"; } }
Java
볡사
인증된 μ‚¬μš©μž κΆŒν•œμ΄ 관리(ROLE_ADMIN) 인지 κ²€μ¦ν•©λ‹ˆλ‹€.
νŒŒλΌλ―Έν„°λ‘œ κ²Œμ‹œκΈ€ id 와 인증된 μ‚¬μš©μž no 받아와 κ²Œμ‹œκΈ€ μ†Œμœ μžλ₯Ό ν™•μΈν•©λ‹ˆλ‹€.