의존성 참고!
// Sprint Security
implementation 'org.springframework.boot:spring-boot-starter-security'
// OAuth2
implementation group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.3.5.RELEASE'
// JWT
implementation group: 'org.springframework.security', name: 'spring-security-jwt', version: '1.1.1.RELEASE'
1. @EnableGlobalMethodSecurity 설정
MethodSecurity는 말그대로 메소드 수준에서 권한을 제어할 수 있도록 해준다!
특정 메소드마다 실행할 수 있는 역할을 제한할 수 있도록 해줌.
단순히 허용, 거부 하는 것 보다 더 복잡한 규칙을 적용할 수 있음.
GlobalMethodSecurity 사용을 활성화 하는 @EnableGlobalMethodSecurity 어노테이션을 추가
- prePostEnabled - Spring Security의 @PreAuthorize, @PreFilter /@PostAuthorize, @PostFilter어노테이션 활성화 여부
- securedEnabled - @Secured어노테이션 활성화 여부
- jsr250Enabled - @RoleAllowed 어노테이션 사용 활성화 여부
@Configuration
@EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class MethodSecurityConfig
extends GlobalMethodSecurityConfiguration {
}
실제로는 아래와 같이 설정해주었다. prePostEnabled만 true로 활성화
OAuth2MethodSecurityExpressionHandler()는.. OAuth2를 사용한다면 해주어야 함..!
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
2. @PreAuthorize 사용!
@PreAuthorize는 해당 메서드가 호출되기 이전에 검사한다. 실제로 해당 메서드를 호출할 권한이 있는지를 확인!
(PostAuthorize는 메서드 호출 이후)
주석처리된 코드에서도 알 수 있듯.. 원래는 endpoint마다 저 코드를 복붙하여 username이라는 PathVariable을 검사하고...
관리자 권한(ROLE_ADMIN)이 없는데 본인 id(username)이 아닌 남의 id를 입력하면 관리자 권한이 없다는 예외처리를 해줬었는데
이제 @PreAuthorize로 간단히 처리할 수 있게 되었다!
@ApiOperation(value = "get user info", notes = "유저 정보 조회 me 혹은 유저 id로 조회 가능")
@GetMapping(value = "/{username}", produces = "application/json")
@PreAuthorize("#username == 'me' or #username == authentication.name or hasRole('ROLE_ADMIN')")
public ResponseEntity<?> getUserInfo(Authentication authentication,
@ApiParam(value = "username 혹은 me", required = true)
@PathVariable(name = "username") String username) {
// if(username.equals("me") || username.equals(authentication.getName()) ||
// authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))) {
// return ResponseEntity.ok().body(userService.findByName(username.equals("me") ? authentication.getName() : username));
// }else {
// throw new AccessDeniedException("관리자 권한이 필요합니다.");
// }
return ResponseEntity.ok().body(userService.findByName(username.equals("me") ? authentication.getName() : username));
}
* returnObject를 이용해 반환값에 접근할 수도 있다.
@PreAuthorize("returnObject.name == #username")
3. 더 간단히.. Method로 권한여부 체크하기!
webSecurity라는 Bean/Component에 정의된 public boolean 메서드를 이용해 권한 여부를 체크할 수 있다.
@PreAuthorize("@webSecurity.checkAuthority(authentication,#username)")
메서드 안에 권한 여부를 체크하는 코드를 작성하고..
@Component("webSecurity")
public class WebSecurity {
public boolean checkAuthority(Authentication authentication, String userid) {
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_ADMIN"))
|| userid.equals("me") || userid.equals(authentication.getName()) ) {
return true;
}else {
return false;
}
}
}
실행 했는데 org.springframework.expression.spel.SpelEvaluationException가 발생하면!
MethodSecurityConfig를 수정해 ApplicationContext를 등록해준다.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext applicationContext;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
OAuth2MethodSecurityExpressionHandler oAuth2MethodSecurityExpressionHandler =
new OAuth2MethodSecurityExpressionHandler();
oAuth2MethodSecurityExpressionHandler.setApplicationContext(applicationContext);
return oAuth2MethodSecurityExpressionHandler;
}
}
+) @PreAutorized를 컨트롤러 자체에 적용할 수도 있다!
모든 endpoints에서 @PreAuthorize가 적용된 효과를 볼 수 있음
@PreAuthorize("@methodSecurity.checkAuthority(authentication,#username)")
public class UserController {
/* ... 생략 ... */
}
+) 참고
'STUDY > Spring' 카테고리의 다른 글
Spring Boot | profile설정 ( + 2.4이상 버전 변경내용 추가 ) (0) | 2021.04.05 |
---|---|
Spring Boot | Exception만들기 (0) | 2021.03.29 |
Spring Boot | REST API 파일 업로드 / 다운로드 (1) | 2021.03.23 |
Spring Boot | @ControllerAdvice로 Exception 처리하기 (0) | 2021.03.19 |
Spring Boot | 유효성 검사 직접 만들기! (Custom Constraint) (0) | 2021.03.17 |