SMALL

Spring Security를 처음 접하는 경우 권한 별 접근 제어는 대부분 

WebSecurityConfigurerAdapter를 상속받은 클래스 하위에 configure(HttpSecurity http) 메서드에 설정하게 된다. 

 

public class ServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

	private final LoginService loginService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	    SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
	    successHandler.setTargetUrlParameter("redirectTo");
	    successHandler.setDefaultTargetUrl(this.adminServer.path("/"));

	    http.authorizeRequests(
	        (authorizeRequests) -> authorizeRequests.antMatchers("/assets/**").permitAll() 
	            .antMatchers("/login").permitAll()
	            .antMatchers("/h2-console/**").permitAll()
	            .anyRequest().authenticated() 
	    ).httpBasic(Customizer.withDefaults()) 
	        .csrf((csrf) -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 
	            .ignoringRequestMatchers(
	                new AntPathRequestMatcher("/api/v1/**"),
	                new AntPathRequestMatcher("/h2-console/**")
	                
	            ))
	        .headers().frameOptions().disable().and()
	        .rememberMe((rememberMe) -> rememberMe.key(UUID.randomUUID().toString()).tokenValiditySeconds(1209600));
	}
}

 

 

이 설정 이외에 만약 특정 메서드에서 권한 별 접근 제어를 하고 싶은 경우에는 어떠한 방법이 있는지 알아보도록 하자. 

 

Spring Security에서는 특정 Class, Method에 적용할 수 있는 Annotation을 제공한다.

해당 Annotation을 원하는 위치에 작성하면 해당 클래스 또는 메서드는 권한 체크하는 로직을 타게 된다. 

 

Spring Security에서는 다양한 Annotation을 제공하는데, 오늘은 간단하게 @Secure, @PreAuthorize를 알아보도록 하자.

 

@Secured

@Secured는 특정 권한만 접근이 가능하다는 것을 나타내는 Annotation이다. 

간단하게 특정 기능은 Admin만 이용하게 하고 싶은 경우 위의 Annotation을 붙여주면 된다. 

public class ProjectController {

    private final ProjectService projectService;

    @PostMapping("/api/v1/project")
    @Secured("ROLE_ADMIN")
    public String save(@RequestBody ProjectSaveRequestDto requestDto) throws DuplicateException {

        return projectService.save(requestDto);
    }
}

 

만약에 단순하게 특정 권한을 가진 사람이 아닌 다양한 조건이 들어가야 되는 경우에는 @Secured로 표현하기는 조금 힘들게 된다.

이러한 경우에는 @PreAuthorize, @PostAuthorize를 이용하면 좀 더 복잡한 케이스도 처리할 수 있게 된다.

해당 Annotation에서는 SpringEL을 사용할 수 있어서 다양한 권한에 따른 처리가 가능하다. 

 

Spring Expression Language에서는 다양한 Built-in expression을 제공한다. 

아래의 예시에서는 " isAutheticated()" 를 사용하였다. 

Spring EL에서 제공하는 Expression을 숙지하고 있으면 사용자가 직접 기능을 만들지 않고도 활용할 수 있어 유용하다. 

 

https://docs.spring.io/spring-security/reference/servlet/authorization/expression-based.html#el-common-built-in

 

Expression-Based Access Control :: Spring Security

Any Spring-EL functionality is available within the expression, so you can also access properties on the arguments. For example, if you wanted a particular method to only allow access to a user whose username matched that of the contact, you could write

docs.spring.io

 

@PreAuthorize("isAuthenticated() and (( #user.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "", method = RequestMethod.PUT)
public ResponseEntity<Project> updateProject( User user ){
    updateProject.update( user );
    return new ResponseEntity<Project>( new Project(), HttpStatus.OK );
}

@PreAuthorize

추가적으로 @PreAuthorize 내에 #user.name를 사용한 부분을 보면

Annotation이 붙은 Method의 Param값을 위와 같이 활용하여 사용할 수 있게 된다. 

 

@PostAuthorize

@PostAuthorize의 경우에는 Method가 실행된 이후의 return값을 활용할 수 있다. 

아래와 같이 returnObject.name과 같이 "returnObject"를 사용하면 된다. 

@PostAuthorize("isAuthenticated() and (( returnObject.name == principal.name ) or hasRole('ROLE_ADMIN'))")
@RequestMapping( value = "/{id}", method = RequestMethod.GET )
public Project getProject( @PathVariable("id") long id ){
    return service.findOne(id);
}

 

Annotation 활성화 설정 추가

추가적으로, 이러한 Annotation을 활성화 시키기 위해서는 설정을 추가해 주어야 한다. 

@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)

@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ServerSecurityConfiguration extends WebSecurityConfigurerAdapter {

	private final LoginService loginService;
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	    
        //.....
   }
}
LIST

+ Recent posts