이 블로그는 개인의 공부 목적으로 작성된 블로그입니다. 왜곡된 정보가 포함되어 있을 수 있습니다.
권한 (Authorization)
보안 시스템이 인증, 인가를 제공한다는 것을 들어본적 있을 것이다. 인증이 리소스의 호출자를 판단하는 것이라면 인가는 요청을 승인하는 것으로 권한 부여(Authorization)이 이에 해당한다. 스프링 시큐리터에서는 다음과 같은 순서를 권한부여를 따른ㄴ다.
- 클라이언트의 요청
- 인증 필터에서 인증을 요청(Authentication Manager에게 위임) or 이미 인증되어이있다면 Security Context에서 인증 정보를 조회
- 인증필터가 권한 부여 필터에게 위임
- 권한 부여 필터가 권한을 확인
- 컨트롤러에게 전달
GrantedAuthority
우리는 이전에 UserDetails 인터페이스를 구현하여 사용자를 정의 할 수 있고, 이때 구현제에 GrantedAuthority 배열을 반환하는 getAuthories 함수가 있었다.
public interface UserDetails extends Serializable {
String getUserName();
String getPassword();
Collection<? extends GrantedAuthority>getAuthorities();
//중략
}
따라서 GrantedAuthority를 확인함으로서 권한(인가)을 구현할 수 있다.
SpringSecurity에서는 GrantedAuthority를 확인하는 몇가지의 메소드를 제공하고 있다.
- hasAuthority(): 해당 권한이 있는 사용자들만 엔드포인트를 호출할 수 있다.
- hasAnyAuthority(): 파라미터의 여러 권한중 하나라도 있는 사용자들에게 엔드포인트를 허락한다
- access(): SpEL 기반의 권한 부여 규칙 메소드 (권장하지 않음)
해당 메서드를 HttpSecurity에 사용하여 권한부여 규칙을 만들 수 있다.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().hasAuthority("read")
)
.authenticationProvider(customAuthenticationProvider())
.httpBasic(c -> {
c.realmName("OTHER");
c.authenticationEntryPoint(new CustomEntryPoint());
})
.formLogin(forLogin -> forLogin
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
);
return http.build();
}
hasAuthority("read") 을 통해 접근권한을 설정 한 것을 확인 할 수 있다. 그러나 우리는 인증에 있어서 AuthenticationSuccessHandler의 구현체에서 equals("read")와 같이 접근 권한을 설정할 수 있었다. 이 방법이 더 좋아 보인다. 엔드포인트에 따라 선택적으로 권한 부여하는 경우에는 고민해봐야 한다.
@Component
public class CustomAuthenticationSuccessHandler implements org.springframework.security.web.authentication.AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
Optional<? extends GrantedAuthority> auth = authorities.stream()
.filter(a -> a.getAuthority().equals("read"))
.findFirst();
if(auth.isPresent()){
response.sendRedirect("/home");
}
else{
response.sendRedirect("/error");
}
}
}
이제 우리는 이전에 사용했던 메소드들의 의미를 알 수 있는데, permitAll(), denyAll()이 그예이다.
- permitAll() 모든 권한에 대해 해당 엔드포인트 접근을 허락하겠음
- denyAll() 모든 권한에 대해서 해당 엔드포인트 접근을 무조건 거부하겠음
선택기(matcher)를 활용한 권한 부여
위의 방법은 권한과 역활을 기준으로 접근 권한을 부여한다면 특정한 요청 그룹에 대해서 접근 권한을 사용하기 위해서는 선택기를 사용할 수 있다. 경로별로 권한을 분리하는 것이 대표적인 상황이다.
SpringSecurity에서는 3가지의 선택기 메서드의 유형이 존재한다.
MVC 선택기 : MVC 식을 활용하여 엔드포인트 선택엔트 선택기 : 엔트 식을 활용하여 엔드포인트 선택정규식 선택기 : 정규식을 활용하여 엔드포인트 선택
SpringSecurity 6.0 이상에서는 3가지의 편집기를 deprecated로 지정하고 통일된 requestMatcher를 사용하도록 변경되었음
https://docs.spring.io/spring-security/reference/5.8/migration/servlet/config.html
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().hasAuthority("read")
.requestMatchers("/hello1").hasRole("admin")
.requestMatchers("/hello2").hasRole("user")
)
.authenticationProvider(customAuthenticationProvider())
.httpBasic(c -> {
c.realmName("OTHER");
c.authenticationEntryPoint(new CustomEntryPoint());
})
.formLogin(forLogin -> forLogin
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
);
return http.build();
}
requestMatchers("/hello1").hasRole("admin") 와 requestMatchers("/hello2").hasRole("user") 와 같이 엔트포인트를 구별하여 권한을 설정할 수 있음. 이때까지 우리가 사용했던 anyRequest()은 모든 엔트포인트에 대해서 설정하겠다는 의미였다.
또한 경로식으로 엔드포인트를 정의할 수 있다.
ex) requestMatchers("/hello1/**").hasRole("admin") /hello1로 시작하는 모든 경로에 대한 요청 처리
requestMatchers("/**/hello1").hasRole("admin") /hello1를 포함하는 모든 경로에 대한 요청 처리
정규식도 사용 가능
config에 일일히 엔드포인트명시하는 것이 별로 좋지 않은 개발방법 같은데 더 좋은 방법을 생각해볼것
'보안' 카테고리의 다른 글
[Spring Security in action] CSRF 보호 및 CORS 적용 (0) | 2024.02.03 |
---|---|
[Spring Security in action] 인증 필터 (0) | 2024.01.20 |
[Spring Security in action] SecurityContext (0) | 2024.01.18 |
[Spring Security in action] AuthenticationProvider을 사용한 인증 (0) | 2024.01.16 |
[Spring Security in action] 사용자 관리 (0) | 2024.01.15 |