Не удается вычислить выражение SpEL со списком строк

#acl #spring-el

#acl #spring-el

Вопрос:

Обновление от 27 октября

Следующий метод имеет аннотацию ACL на основе SpEL. Это предназначено для проверки того, имеет ли файловый объект fileId разрешения Read и Write . Если файловый объект содержит любое из двух разрешений, ACL передается, в противном случае создается исключение.

 @Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    public FileListVO getFiles(String fileId) {
        ...
    }
}
  

Аннотация находится через acl компонент ниже.

 public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}
  

Вопрос в том, что приведенное ниже выражение SpEL не может быть вычислено:

 @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
  
 java.lang.IllegalArgumentException: Failed to evaluate expression '@acl.hasPermissions('File',{'Read','Write'}, #fileId)'
There is a List<String> permissions in it. What is the correct expression for this?
  

Пожалуйста, обратите внимание, что throw exception поведение в AclServiceImpl.hasPermissions() устаревшем коде, которое я не хочу менять. @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)") ожидается, что оно вернет true исключение, не вызывающее исключение. Я знаю, что следующим вариантом может быть следующее,

 public interface AclService {
    boolean hasPermission(String type, String permission, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermission(String type, String permission, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains permission) {
            return true;
        }
        return false; // not throw exception
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File','Read', #fileId)"
          "|| @acl.hasPermissions('File','Write', #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}
  

но мне просто интересно, как улучшить

 @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
  

так что следующий код работает.

 public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    public FileListVO getFiles(String fileId) {
        ...
    }
}
  

Ответ №1:

здесь возникает исключение

Конечно, оценка завершается неудачей, если вы создаете там исключение.

Вместо этого вы должны вернуть false .

Комментарии:

1. Спасибо, @Gary! То, что я на самом деле спрашиваю, опубликовано ниже.

2. Не следует добавлять ответ для уточнения вопроса; вместо этого отредактируйте вопрос. Самое простое решение — написать компонент-оболочку вокруг существующего компонента ACL, который улавливает исключение и возвращает false. Невозможно перехватить исключение в самом SpEL. @PreAuthorize("@aclWrapper.hasPermissions('File',{'Read','Write'}, #fileId)") .

3. Вопрос обновлен. Просто интересно, как улучшить @PreAuthorize("@aclWrapper.hasPermissions('File',{'Read','Write'}, #fileId)") … Я знаю @PreAuthorize("@acl.hasResPermissions('PostMeeting', new String[]{'Read','CO_Read'}, #meetingUUID)") , что это тоже не работает, но каков правильный формат?

4. То, что у вас отлично работает для меня, SpEL создает список<String> для второго аргумента. Я протестировал его как чистый SpEL (не в spring security), но это не должно иметь значения. Если у вас все еще возникают проблемы, я посмотрю завтра.

Ответ №2:

Со следующими изменениями это работает. Не уверен, что требуется 1-е изменение, но 2-е изменение обязательно.

  1. Заменить List<String> на String[] для permissions
  2. Заменить {'Read','Write'} на new String[]{'Read','Write'}

Перед

 public interface AclService {
    boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, List<String> permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    @PreAuthorize("@acl.hasPermissions('File',{'Read','Write'}, #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}
  

После

 public interface AclService {
    // Replace List<String> with String[]
    boolean hasPermissions(String type, String[] permissions, Object resource, Object... resourceContext);
}

@Component("acl")
public class AclServiceImpl implements AclService {

    @Override
    public boolean hasPermissions(String type, String[] permissions, Object resource, Object... resourceContext) {
        List<String> resourcePermissions = get permissions of resource
        if (resourcePermissions contains any of permissions) {
            return true;
        }
        throw exception here
    }
}

@Component
public class ApiImpl {
    // Replace {'Read','Write'} with new String[]{'Read','Write'}
    @PreAuthorize("@acl.hasPermissions('File',new String[]{'Read','Write'}, #fileId)")
    @PostMeetingTelemetry()
    public FileListVO getFiles(String fileId) {
        ...
    }
}