我正在将应用程序从 Symfony 3.4 迁移到 Symfony 4.4。此应用程序使管理员用户可以编辑访问每条路线所需的角色,因此所有角色和路线都存储在数据库中。
为了检查用户是否可以访问路由,每个请求都会调用一个投票者,并在services.yaml
文件中进行配置。
在 Symfony 3.4 中,每个请求都会调用投票者,而无需添加任何代码。在网络分析器中,我可以看到选民名单,以及 AccessDecisionManager 的决定(“授予”或“拒绝”)。
Symfony 3.4 的 Web Profiler 的屏幕截图
然而,在 Symfony 4.4 中,选民似乎根本没有被召唤。在网络分析器中,我的自定义选民仍在列表中(两次??),但没有来自 AccessDecisionManager 的决定。
Symfony 4.4 的 Web Profiler 的屏幕截图
如果我通过添加此行直接从控制器检查用户访问权限$this->denyAccessUnlessGranted("", $request);
,则会调用选民并按预期工作。
如果有人可以向我解释为什么我必须denyAccessUnlessGranted()
在 Symfony 4.4 中手动调用 Symfony 3.4 中不需要的方法?我在 3.4 中是否以错误的方式使用选民?
谢谢你。
我的自定义选民类:
namespace App\Security;
use Doctrine\ORM\EntityManager;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
class DynamicAccessVoter implements VoterInterface
{
// Routes everyone has access to
const PUBLIC_ROUTES = [
"login"
];
// Routes everyone who's connected has access to
const PRIVATE_ROUTES = [
"homepage",
"fos_js_routing",
"fos_js_routing_js"
];
// Routes everyone has access to only in dev mode
const DEV_ROUTES = [
"_wdt",
"_profiler",
"_profiler_home",
"_profiler_search",
"_profiler_search_bar",
"_profiler_phpinfo",
"_profiler_search_results",
"_profiler_open_file",
"_profiler_router",
"_profiler_exception",
"_profiler_exception_css",
"_twig_error_test"
];
private $env;
/**
* Constructor
*
* @param string $env - App environment (dev or prod)
*/
public function __construct(String $env = "") {
$this->env = $env;
}
/**
* Custom voter
*
* @param TokenInterface $token
* @param Request $subject
* @param array $env
*/
public function vote($token, $subject, $attributes) {
// Verifie si $subject est une instance de Request
if(!$subject instanceof Request) {
return self::ACCESS_ABSTAIN;
}
$route = $subject->attributes->get("_route");
// Verifie si la route est une route publique (accessible par tout le monde)
if(in_array($route, DynamicAccessVoter::PUBLIC_ROUTES)) {
return self::ACCESS_GRANTED;
}
// Verifie si l'application est en développement et la route nécéssaire pour le debug
if($this->env == "dev" && in_array($route, DynamicAccessVoter::DEV_ROUTES)) {
return self::ACCESS_GRANTED;
}
// Verifie si $utilisateur est une instance de UserInterface
if(!$token->getUser() instanceof UserInterface) {
return self::ACCESS_ABSTAIN;
}
// Verifie si la route est une route accéssible par tout utilisateur connecté
if(in_array($route, DynamicAccessVoter::PRIVATE_ROUTES)) {
return self::ACCESS_GRANTED;
}
// Verifie si l'utilisateur connecté à le droit d'accéder à cette route
if($token->getUser()->hasAccessTo($route)) {
return self::ACCESS_GRANTED;
}
return self::ACCESS_DENIED;
}
}
我的自定义选民在 services.yaml 文件中配置为服务:
app.dynamic_access_voter:
class: App\Security\DynamicAccessVoter
arguments: ["%kernel.environment%"]
tags:
- { name: security.voter }
我的 security.yaml 文件,如果有帮助的话:
security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
encoders:
App\Entity\Utilisateur:
algorithm: bcrypt
providers:
main:
entity:
class: App\Entity\Utilisateur
property: email
firewalls:
main:
anonymous: true
provider: main
pattern: ^/
form_login:
login_path: login
check_path: login
always_use_default_target_path: true
default_target_path: homepage
logout:
path: /logout
target: /login
user_checker: App\Security\EnabledUserChecker
access_control:
- { path: ^/ }