Потому что задача фильтра проверить есть ли доступ к действию или нет.
Он может вернуть true или false, рендерить ответ - задача контроллера.
Внутри beforeAction можно вызвать исключение, которое перехватит errorHandler, ну а там в errorHandler->errorAction вы можете зарендерить ошибку