시큐리티를 활용한 접근제한

심규환·2022년 2월 22일
2

Spring Security

목록 보기
2/3

스프링 시큐리티를 사용해서 다른 접근 제한 기능을 알아서 정리하고자 합니다.. 일반적으로 SecurityConfig에서 아래와 같이 사용 했었는데.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        log.info("security config..");

        http.formLogin().disable()
                .httpBasic().disable();

        http.cors();

        http.csrf().disable();

        // JWT 관련 필터 보안 컨텍스트에 추가와 세션 STATELESS 설정
        http.addFilterAt(new JwtAuthenticationFilter(authenticationManager(), jwtTokenProvider),
                        UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new JwtRequestFilter(jwtTokenProvider),UsernamePasswordAuthenticationFilter.class)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.authorizeRequests()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                .antMatchers("/").permitAll()
                .antMatchers("/codes/**").permitAll()

제일 아래에 http.authorizeRequests() 이후 부터 정적 파일과 "/", "/codes/****" 접근을 모두 허용 하도록 설정했습니다.

만약 /codes/ 아래에 간단하게 코드 등록, 수정, 삭제, 조회의 API가 있을 때, 수정과 삭제는 관리자만 허용하고 MEMBER는 등록과 조회를 허용하게 한다고 해봅시다.
그러면 세부 사항부터 설정하고 큰 범위를 설정하게 됩니다.
.antMatcher("/codes/remove").hasRole("ADMIN")
.antMatcher("/codes/register").hasRole("ADMIN")
.antMatcher("/codes/****).permitAll()

위와 같은 방식으로도 가능하지만 시큐리티에서는 애너테이션을 활용해서 접근 제한을 줄 수 있는 방법이 있습니다.

먼저 SecurityConfig 상단에 아래의 애너테이션을 추가합니다.

// 시큐리티 애너테이션 활성화
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{

prePostEnabled와 securedEnabled는 기본값이 false 이며, 다른 곳, 예를 들어서 컨트롤러에 PreAuthorize 또는 PostAuthorize, "Secured"를 적용하여 접근제한을 할 수 있도록 해줍니다.

  • PreAuthorize는 메서드에 접근 전에 권한을 확인합니다. 만약 권한이 없다면 403 에러를 보냅니다.
  • PostAuthorize는 메서드 접근 후 리턴값을 보내기 전에 권한을 확인 합니다.
  • Secured는 메서드에 접근 권한이 없으면 403 에러를 보냅니다.

간단한 사용 예시입니다.

	// ADMIN의 접근만 허용
    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping
    public ResponseEntity<List<Member>> list() throws Exception{
        return new ResponseEntity<>(service.list(), HttpStatus.OK);
    }
	// ADMIN, MEMBER의 접근 허용
	@PreAuthorize("hasAnyRole('ADMIN','MEMBER'")
    @PutMapping("/{userNo}")
    public ResponseEntity<Member> modify(@PathVariable("userNo")Long userNo, @Validated @RequestBody Member member) throws Exception{
        member.setUserNo(userNo);
        service.modify(member);

        return new ResponseEntity<>(member, HttpStatus.OK);
    }

이를 간단하게 @Secured({"ADMIN", "MEMBER"}) 설정이 가능합니다.(SpEL)

@PreAuthorize 조건 작성시, 아래의 정보를 활용해서 조건식도 사용이 가능합니다.

hasRole([role]) : 현재 사용자의 권한이 파라미터의 권한과 동일한 경우 true
hasAnyRole([role1,role2]) : 현재 사용자의 권한디 파라미터의 권한 중 일치하는 것이 있는 경우 true
principal : 사용자를 증명하는 주요객체(User)를 직접 접근할 수 있다.
authentication : SecurityContext에 있는 authentication 객체에 접근 할 수 있다.
permitAll : 모든 접근 허용
denyAll : 모든 접근 비허용
isAnonymous() : 현재 사용자가 익명(비로그인)인 상태인 경우 true
isRememberMe() : 현재 사용자가 RememberMe 사용자라면 true
isAuthenticated() : 현재 사용자가 익명이 아니라면 (로그인 상태라면) true
isFullyAuthenticated() : 현재 사용자가 익명이거나 RememberMe 사용자가 아니라면 true

사용 예시>

/boards/** 로 GET 접근으로 온다면 모두 허용이며 아니면 'MEMBER'와 "ADMIN'만 가능하다.
.antMatchers("/boards/**").access("request.method == 'GET' ? permitAll : hasAnyRole('MEMBER', 'ADMIN' )")
profile
장생농씬가?

0개의 댓글