You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Symfony Workflow:能否按用户角色与文章状态配置访问权限?

问题:能否通过Symfony Workflow配置控制实体访问权限?

你当前的Symfony工作流配置如下:

framework:
    workflows: 
        post_publishing:
            type: 'state_machine'
            marking_store:
                type: 'method'
                property: 'state'
            supports:
                - App\Entity\Post
            initial_marking: pending
            places:
                - pending
                - draft
                - published
                - archived
            transitions:
                to_draft:
                    guard: "is_granted('ROLE_ADMIN')"
                    from: pending
                    to: draft
                to_publish:
                    guard: "is_granted('ROLE_USER')"
                    from: draft
                    to: published
                to_archived:
                    guard: "is_granted('ROLE_USER')"
                    from: [published, draft]
                    to: archived

你的需求是:

  • 未认证用户仅能查看已发布文章
  • 认证用户(ROLE_USER)可查看草稿与已发布文章
  • 管理员(ROLE_ADMIN)可查看所有状态的文章

首先明确:Workflow Bundle的配置是用来管控状态转换权限的(比如谁能把草稿改成已发布),没法直接在Workflow配置里实现实体的访问权限控制。实体访问权限属于数据层面的授权逻辑,应该用Symfony Security组件的自定义Voter来实现,结合文章的状态和用户角色即可。

下面是具体的实现步骤:

1. 创建自定义Voter

生成一个PostVoter类,用来处理文章的访问权限判断:

// src/Security/Voter/PostVoter.php
namespace App\Security\Voter;

use App\Entity\Post;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\User\UserInterface;

class PostVoter extends Voter
{
    // 定义要检查的权限标识
    public const VIEW = 'VIEW_POST';

    protected function supports(string $attribute, mixed $subject): bool
    {
        // 只处理VIEW_POST权限和Post实体的校验
        return $attribute === self::VIEW && $subject instanceof Post;
    }

    protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();
        // 未认证用户仅允许查看已发布文章
        if (!$user instanceof UserInterface) {
            return $subject->getState() === 'published';
        }

        // 管理员直接拥有所有文章的查看权限
        if ($token->isGranted('ROLE_ADMIN')) {
            return true;
        }

        // 普通认证用户允许查看草稿和已发布状态的文章
        $allowedStates = ['draft', 'published'];
        return in_array($subject->getState(), $allowedStates);
    }
}

2. 在业务逻辑中使用权限校验

在控制器获取文章列表时,建议结合角色和状态做数据库层面的筛选(性能更优):

// 控制器示例
public function index(EntityManagerInterface $em, AuthorizationCheckerInterface $authChecker): Response
{
    $qb = $em->createQueryBuilder()
        ->select('p')
        ->from(Post::class, 'p');

    $user = $this->getUser();
    if (!$user) {
        // 未认证用户仅查询已发布文章
        $qb->where('p.state = :state')
            ->setParameter('state', 'published');
    } elseif (!$authChecker->isGranted('ROLE_ADMIN')) {
        // 普通认证用户查询草稿和已发布文章
        $qb->where('p.state IN (:states)')
            ->setParameter('states', ['draft', 'published']);
    }
    // 管理员无需过滤,直接查询所有文章

    $posts = $qb->getQuery()->getResult();

    return $this->render('post/index.html.twig', [
        'posts' => $posts,
    ]);
}

在Twig模板中单独判断单篇文章的访问权限:

{% for post in posts %}
    {% if is_granted('VIEW_POST', post) %}
        <div class="post-item">
            <h3>{{ post.title }}</h3>
            <p>{{ post.content }}</p>
        </div>
    {% endif %}
{% endfor %}

内容的提问来源于stack exchange,提问作者Shoooryuken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 07:06:25