[Spring Security] 인가를 위한 권한설정과 표현식 알아보기

식빵·2022년 8월 13일
4
post-thumbnail

이 시리즈에 나오는 모든 내용은 인프런 인터넷 강의 - 스프링 시큐리티 - Spring Boot 기반으로 개발하는 Spring Security - 에서 기반된 것입니다. 그리고 여기서 인용되는 PPT 이미지 또한 모두 해당 강의에서 가져왔음을 알립니다.



🐳 권한 설정 방식 2가지


1. 선언적 방식

  • URL 단위
    http.antMatchers("/users/**").hasRole("USER")
  • Method 단위
@PreAuthorize("hasRole('USER')")
public void user() {~}

2. 동적 방식(=DB 연동)

  • URL 단위
  • Method 단위

일단 간단한 선언적 방식을 이번 게시글에서 알아보고,
동적 방식은 할 게 많으니 추후에 알아보겠다.



🐳 선언적 방식 - URL 단위 API 목록

메소드동작
authenticated()인증된 사용자의 접근을 허용
fullyAuthenticated()인증된 사용자의 접근을 허용, rememberMe 인증 제외
permitAll()무조건 접근을 허용
denyAll()무조건 접근을 허용하지 않음
anonymous()익명사용자의 접근을 허용
rememberMe()기억하기를 통해 인증된 사용자의 접근을 허용
access(String)주어진 SpEL 표현식의 평가 결과가 true이면 접근을 허용
hasRole(String)사용자가 주어진 역할이 있다면 접근을 허용
hasAuthority(String)사용자가 주어진 권한이 있다면
hasAnyRole(String...)사용자가 주어진 권한이 있다면 접근을 허용
hasAnyAuthority(String...)사용자가 주어진 권한 중 어떤 것이라도 있다면 접근을 허용
hasIpAddress(String)주어진 IP로부터 요청이 왔다면 접근을 허용

주의할 점

1: 로그인 사용자, 익명 사용자 모두 접근 가능하려면 permitAll().
anonymous() 는 오로지 익명사용자만 가능하다.

2: hasRole("USER") , hasAuthority("ROLE_USER") 처럼 사용법이 다름




🐳 API 사용한 권한 설정


1. Spring Security 설정 클래스

@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private UserDetailsService userDetailsService;
    
    
    // 동적으로 사용자와 동시에 권한도 설정
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        
        auth.inMemoryAuthentication().withUser("user").password("{noop}1111").roles("USER");
        auth.inMemoryAuthentication().withUser("sys").password("{noop}1111").roles("SYS");
        auth.inMemoryAuthentication().withUser("admin").password("{noop}1111").roles("ADMIN");
        
        // 그런데 만약 admin 에게 USER, SYS 권한도 주고 싶으면 어떡할가?
        // auth.inMemoryAuthentication()
		//    .withUser("admin").password("{noop}1111").roles("ADMIN", "SYS", "USER");
        // 하지만 이런 권한 관계가 계층적으로 관리하고 싶을 것이다. 
        // 또한 동적으로 권한을 줬다 뺏다하는 것도 하고 싶을 것이다.
        // 그건 추후에 DB로 권한 관리를 할 때 알아볼 것이다.
        // 지금은 선언적 방식의 사용법을 알아가고 넘어가자.
    }
    
    
    // URL 단위로 매핑
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http
            .authorizeRequests()
            .antMatchers("/api/user").hasRole("USER")
            .antMatchers("/api/systemLog").hasRole("SYS")
            .antMatchers("/api/admin/**").access("hasRole('ADMIN') or hasRole('SYS')")
            .anyRequest().authenticated();
    
        http.formLogin();
        
    }
}

주의할 점이 있다!
만약에 아래처럼 설정했다면 어떻게 됐을까?

.antMatchers("/api/admin/**").access("hasRole('ADMIN') or hasRole('SYS')")
.antMatchers("/api/systemLog").hasRole("SYS")

이러면 ADMIN, SYS 권한 모두 /api/systemLog url 에 접근이 된다.
항상 더 자세한 url 이 먼저 나오도록 작성해야 한다는 점을 기억하자.



2. 요청을 받는 예제 RestController 생성

@RestController
public class SecurityController {
    
    @GetMapping("/")
    public String index() {
        return "home";
    }
    
    @GetMapping("/api/user")
    public String user() {
        return "user";
    }
    
    @GetMapping("/api/systemLog")
    public String systemLog() {
        return "systemLog";
    }
    
    @GetMapping("/api/admin/**")
    public String admin() {
        return "admin";
    }
}

사실 선언적 방식은 어떤 자원 경로에 permitAll 해주는 용도로 많이쓰고,
추후에 알아볼 DB 연동 권한 체크에서 더 세세한 관리를 한다.
그러니 이정만 작성하고 그냥 넘어가겠다. 궁금하면 위 코드를 갖고 여러가지 실험하기.

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글