복붙노트

[SPRING] Spring Security @ PreAuthorize / @ PostAuthorize 어노테이션에서 커스텀 표현식을 사용하는 방법

SPRING

Spring Security @ PreAuthorize / @ PostAuthorize 어노테이션에서 커스텀 표현식을 사용하는 방법

@Preauthorize 블록에서보다 풍부한 표현 문을 작성하는 방법이 있습니까? @Preauthorize가 매우 똑똑하지 않기 때문에 반복되는 것을 발견하는 예가 있습니다.

@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public void deleteGame(@PathVariable int id, @ModelAttribute User authenticatingUser) {
    Game currentGame = gameService.findById(id);
    if(authenticatingUser.isAdmin() || currentGame.getOwner().equals(authenticatingUser)) {
        gameService.delete(gameService.findById(id));
    } else {
        throw new SecurityException("Only an admin, or an owner can delete a game.");
    }
}

내가 좋아할만한 것이 있습니다.

@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
@Preauthorize(isAdmin(authenicatingUser) OR isOwner(authenicatingUser, id)
public void deleteGame(@PathVariable int id, @ModelAttribute User authenticatingUser, @ModelAttribute currentGame ) { //I'm not sure how to add this either :(
   gameService.delete(gameService.findById(id));
}

문제의 일부는 데이터베이스에 질의하여 게임 복사본을 얻은 다음이 게임 소유자를 제작자와 비교하는 것과 같이 사용 권한을 확인하기 위해이 물건 중 일부를 가져 오기 위해 데이터베이스에 쿼리를해야한다는 것입니다. 요청. 나는 모든 것이 어떻게 @Preauthorize 주석 처리기의 컨텍스트 내에서 작동하는지, 또는 @Preauthorize ( "") 값 속성에서 사용 가능한 객체 컬렉션에 어떤 것을 추가하는지에 대해 잘 모르겠습니다.

해결법

  1. ==============================

    1.1) 먼저 메서드 별 기능이 추가 된 MethodSecurityExpressionRoot를 다시 구현해야합니다. 최초의 스프링 시큐리티 구현은 private 패키지이므로 확장하기 만 할 수는 없습니다. 주어진 클래스의 소스 코드를 확인하는 것이 좋습니다.

    1) 먼저 메서드 별 기능이 추가 된 MethodSecurityExpressionRoot를 다시 구현해야합니다. 최초의 스프링 시큐리티 구현은 private 패키지이므로 확장하기 만 할 수는 없습니다. 주어진 클래스의 소스 코드를 확인하는 것이 좋습니다.

    public class CustomMethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
    
        // copy everything from the original Spring Security MethodSecurityExpressionRoot
    
        // add your custom methods
    
        public boolean isAdmin() {
            // do whatever you need to do, e.g. delegate to other components
    
            // hint: you can here directly access Authentication object 
            // via inherited authentication field
        }
    
        public boolean isOwner(Long id) {
            // do whatever you need to do, e.g. delegate to other components
        }
    }
    

    2) 다음으로 위에 정의 된 CustomMethodSecurityExpressionRoot를 사용할 사용자 지정 MethodSecurityExpressionHandler를 구현해야합니다.

    public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
    
        private final AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
    
        @Override
        public void setReturnObject(Object returnObject, EvaluationContext ctx) {
            ((MethodSecurityExpressionRoot) ctx.getRootObject().getValue()).setReturnObject(returnObject);
        }
    
        @Override
        protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
            MethodInvocation invocation) {
            final CustomMethodSecurityExpressionRoot root = new CustomMethodSecurityExpressionRoot(authentication);
            root.setThis(invocation.getThis());
            root.setPermissionEvaluator(getPermissionEvaluator());
            root.setTrustResolver(this.trustResolver);
            root.setRoleHierarchy(getRoleHierarchy());
    
            return root;
        }
    }
    

    3) 컨텍스트에서 표현식 핸들러 빈을 정의한다. XML을 통해 다음과 같이 할 수 있습니다.

    <bean id="methodSecurityExpressionHandler"
        class="my.package.CustomMethodSecurityExpressionHandler">
        <property name="roleHierarchy" ref="roleHierarchy" />
        <property name="permissionEvaluator" ref="permissionEvaluator" />
    </bean>
    

    4) 위의 정의 된 핸들러 등록

    <security:global-method-security pre-post-annotations="enabled">
        <security:expression-handler ref="methodSecurityExpressionHandler"/>
    </security:global-method-security>
    

    5) 그런 다음 @PreAuthorize 및 / 또는 @PostAuthorize 주석에서 정의 된 표현식을 사용하십시오.

    @PreAuthorize("isAdmin() or isOwner(#id)")
    public void deleteGame(@PathVariable int id, @ModelAttribute currentGame) {
        // do whatever needed
    }
    

    그리고 한 가지 더. 컨트롤러 메소드를 보호하기 위해 메소드 레벨 보안을 사용하는 것이 아니라 비즈니스 로직 (예 : 서비스 계층 메소드)을 사용하여 메소드를 보안하는 것이 일반적입니다. 그런 다음 아래와 같이 사용할 수 있습니다.

    public interface GameService {
    
        // rest omitted
    
        @PreAuthorize("principal.admin or #game.owner = principal.username")
        public void delete(@P("game") Game game);
    }
    

    그러나 이것은 단지 하나의 예에 불과하다는 것을 명심하십시오. 실제 주체에 isAdmin () 메서드가 있고 게임에 소유자의 사용자 이름을 반환하는 getOwner () 메서드가 있다고 예상합니다.

  2. ==============================

    2.@PreAuthorize가 SpEl 표현식을 평가하기 때문에, 가장 쉬운 방법은 단지 콩을 가리키는 것입니다 :

    @PreAuthorize가 SpEl 표현식을 평가하기 때문에, 가장 쉬운 방법은 단지 콩을 가리키는 것입니다 :

        @PreAuthorize("@mySecurityService.someFunction()")
    

    MySecurityService.someFunction에는 반환 유형 boolean이 있어야합니다.

    Spring 보안은 Authentication 객체를 전달하기를 원한다면 자동적으로 authentication이라는 변수를 제공 할 것이다. 유효한 SpEl 표현식을 사용하여 보안 메소드에 전달 된 모든 인수에 액세스하고, 정규 표현식을 평가하고, 정적 메소드를 호출 할 수 있습니다. 예 :

        @PreAuthorize("@mySecurityService.someFunction(authentication, #someParam)")
    
  3. ==============================

    3.다음과 같이 주석을 작성할 수 있습니다.

    다음과 같이 주석을 작성할 수 있습니다.

    @PreAuthorize("hasRole('ROLE_ADMIN') and hasPermission(#id, 'Game', 'DELETE')")
    

    hasPermission 부분을 작동 시키려면 PermissionEvaluator 인터페이스를 구현해야합니다.

    그런 다음 표현식 처리기 bean을 정의하십시오.

    @Autowired
    private PermissionEvaluator permissionEvaluator;
    
    @Bean
    public DefaultMethodSecurityExpressionHandler expressionHandler()
    {
        DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
        handler.setPermissionEvaluator(permissionEvaluator);
        return handler;
    }
    

    보안 설정에 삽입하십시오.

    <global-method-security pre-post-annotations="enabled">
      <expression-handler ref="expressionHandler" />
    </global-method-security>
    
  4. from https://stackoverflow.com/questions/26747452/how-to-use-custom-expressions-in-spring-security-preauthorize-postauthorize-an by cc-by-sa and MIT license