我在 Drupal 8 中使用标志模块面临问题(csrf_token' URL 查询参数无效)
Posted
技术标签:
【中文标题】我在 Drupal 8 中使用标志模块面临问题(csrf_token\' URL 查询参数无效)【英文标题】:I am facing problem (csrf_token' URL query argument is invalid) with flag module at Drupal 8我在 Drupal 8 中使用标志模块面临问题(csrf_token' URL 查询参数无效) 【发布时间】:2021-03-01 15:31:20 【问题描述】:我生成了标志链接
$flag_link = [
'#lazy_builder' => ['flag.link_builder:build', [
$product->getEntityTypeId(),
$product->id(),
'product_like',
]],
'#create_placeholder' => TRUE,
];
标志链接生成成功。但是当我点击标志链接时,我收到错误消息作为响应
message: "'csrf_token' URL query argument is invalid." message: "'csrf_token' URL query argument is invalid."
【问题讨论】:
临时我通过修改 modules/contrib/flag/src/Access/CsrfAccessCheck.php 解决了这个问题只需删除条件: return $this->account->isAnonymous() ? AccessResult::allowed() : $this->original->access($route, $request, $route_match);并添加条件:return AccessResult::allowed(); 以上解决方案不好。请任何人以适当的方式解决这个问题.. Drupal 核心问题:"nojs"/"ajax" route parameter in use-ajax link breaks CSRF protection 【参考方案1】:我找到了一个临时解决方案。不确定这是否是需要由模块维护人员解决的 Flag 中的错误,或者这是否按预期工作,因为这是 REST 响应,而不是典型的 Drupal 调用视图或显示模式。
在 ModuleRestResource.php 文件中(在我的例子中,ModuleRestResource.php 文件位于: DRUPAL_ROOT/web/modules/custom/Module_Name/src/Plugin/rest/resource/Module_NameRestResource.php):
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\flag\FlagService;
use Drupal\Core\Render\RenderContext;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class ModuleRestResource extends ResourceBase
/**
* A current user instance.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* @var $entityTypeManager \Drupal\Core\Entity\EntityTypeManager
*/
protected $entityTypeManager;
/**
* @var \Drupal\flag\FlagService
*/
protected $flagService;
/**
* @var Drupal\Core\Access\CsrfTokenGenerator
*/
protected $csrfService;
/**
* @inheritdoc
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition)
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->logger = $container->get('logger.factory')->get('module');
$instance->currentUser = $container->get('current_user');
$instance->entityTypeManager = $container->get('entity_type.manager');
$instance->flagService = $container->get('flag');
$instance->csrfService = $container->get('csrf_token');
return $instance;
/**
* Responds to GET requests.
*
* @param string $payload
*
* @return \Drupal\rest\ResourceResponse
* The HTTP response object.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function get($payload)
// You must to implement the logic of your REST Resource here.
// Use current user after pass authentication to validate access.
if (!$this->currentUser->hasPermission('access content'))
throw new AccessDeniedHttpException();
if (!is_numeric($payload))
throw new BadRequestHttpException();
/*
* This is the object that will be returned with the node details.
*/
$obj = new \stdClass();
// First load our node.
/**
* @var \Drupal\Core\Entity\EntityInterface
*/
$node = $this->entityTypeManager->getStorage('node')->load($payload);
/**
* FIX STARTS HERE !!!!!
*/
/**
* Because we are rending code early in the process, we need to wrap in executeInRenderContext
*/
$render_context = new RenderContext();
$fl = \Drupal::service('renderer')->executeInRenderContext($render_context, function() use ($node, $payload)
/**
* Get the flag we need and check if the selected node has been flagged by the current user
*
* Set the path to create a token. This is the value that is missing by default that creates an
* invalid CSRF Token. Important to note that the leading slash should be left off for token generation
* and then added to to the links href attribute
*
*/
$flag = $this->flagService->getFlagById('bookmark');
$is_flagged = (bool) $this->flagService->getEntityFlaggings($flag, $node, \Drupal::currentUser() );
$path = 'flag/'. ($is_flagged ? 'un' : '') .'flag/bookmark/' . $node->id();
$token = $this->csrfService->get($path);
$flag_link = $flag->getLinkTypePlugin()->getAsFlagLink($flag, $node);
$flag_link['#attributes']['href'] = '/' . $path . '?destination&token=' . $token;
/**
* Render the link into html
*/
return \Drupal::service('renderer')->render($flag_link);
);
/**
* This is required to bubble metadata
*/
if (!$render_context->isEmpty())
$bubbleable_metadata = $render_context->pop();
\Drupal\Core\Render\BubbleableMetadata::createFromObject($fl)
->merge($bubbleable_metadata);
/*
* !!!!! FIX ENDS HERE !!!!!
*/
$obj->flag_link = $fl;
return new ResourceResponse((array)$obj, 200);
任何可以让模块维护者解决这个问题的人都会很好。
【讨论】:
以上是关于我在 Drupal 8 中使用标志模块面临问题(csrf_token' URL 查询参数无效)的主要内容,如果未能解决你的问题,请参考以下文章
我在 Drupal 的测验模块(Drupal 7,测验版本 7.x-5.2)中看不到反馈