환경
Spring Boot 3.3.3
Spring Security 6.3.3
문제
@PreAuthorize/@Secured - NullPointerException
//WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig {
....
}
//UserController.java
...uesrService 주입..
@PostMapping(value = "/master/create", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@PreAuthorize("hasRole(T(~~.UserRoleEnum).MASTER.getAuthority())")
private ResponseEntity<String> createUserByMaster(
@ModelAttribute @Valid UserCreateDto requestDto
) {
userService.createUserByMaster(requestDto);
return ResponseEntity.ok().body("success");
}
User Role에 따라 Controller에서 차단할 때,
대략 위와 같이 Config에 EnableMethodSecurity를 설정하고 @PreAuthorize 어노테이션을 적용하면, 주입한 userService가 null로 뜨는 에러이다.
+)
hasRole에 Enum 객체 이용하던 다르게 값을 넣던, 아무튼 String이 들어가도록
- hasRole - A shortcut for hasAuthority that prefixes ROLE_ or whatever is configured as the default prefix
예를 들어 "ROLE_MASTER"인 경우
- hasRole('MASTER') : O
- hasRole('ROLE_MASTER') : O
- hasAuthority('MASTER') : X
- hasAuthority('ROLE_MASTER') : O
Expressing Authorization with SpEL 참고
Method Security :: Spring Security
There are some scenarios where you may not wish to throw an AuthorizationDeniedException when a method is invoked without the required permissions. Instead, you might wish to return a post-processed result, like a masked result, or a default value in cases
docs.spring.io
해결
NullPointerException when using @PreAuthorize in Spring Boot
I am working on a Spring Boot project where I have implemented Spring Security to manage JWT authentication. I have a ProductController with a ProductService autowired in it. When I add the @PreAut...
stackoverflow.com
https://github.com/spring-projects/spring-security/issues/8879
NPE when using @PreAuthorize in a Controller inheriting from a base class · Issue #8879 · spring-projects/spring-security
Describe the bug When using @PreAuthorize("isAuthenticated()") on a Controller that inherits from a base class, where both controller classes define methods with a @RequestMapping, dependencies tha...
github.com
//UserController.java
...uesrService 주입..
@PostMapping(value = "/master/create", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@PreAuthorize("hasRole(T(~~.UserRoleEnum).MASTER)")
public ResponseEntity<String> createUserByMaster( //<---public
@ModelAttribute @Valid UserCreateDto requestDto
) {
System.out.println("pass");
userService.createUserByMaster(requestDto);
return ResponseEntity.ok().body("success");
}
security는 proxy를 만들어 메서드 호출을 가로챈다.
controller 메서드 접근자가 공개되어야 security proxy가 접근할 수 있다. private을 public으로 바꿔주면 해결된다.
private으로 하면 proxy가 안되고 권한 접근 제어를 할 수 없다.
그래서 마스터가 아니어도 일단 패스가 되고, 거기에 더해 NPE 에러도 발생한다.
이슈탭 대화에도 나와있는데, 해당 케이스를 설명하는 에러 메시지를 받으면 더 좋을 텐데.
stack trace에서 security proxy를 보고 짐작하기에는, NPE이 짚어볼 부분도 많아서 헛다리 짚기 딱 좋다.