草庐IT

php - Cakephp 3 - 如何在验证过程中检索 'Table' 类中的当前登录用户?

coder 2024-05-02 原文

我正在为我的网站使用 CakePhp3,当我创建或修改实体时,我必须根据当前用户 ID 注入(inject)一些自定义验证逻辑。

基本情况是“用户是否允许将此字段更改为这个新值”?如果不是,我想提出验证错误(或未经授权的异常)。

在 cakephp 中,据我所知,大多数应用程序和业务规则必须放在模型或 ORM 的“模型表”上。但是,在此类中,AuthComponent 或当前 session 不可用。

我不想每次需要检查时都从 Controller 手动调用实体上的方法。我想使用验证器,例如:

$validator->add('protected_data', 'valid', [
            'rule' => 'canChangeProtectedData',
            'message' => __('You're not able to change this data !'),
            'provider' => 'table',
        ]);

模型表上的方法:

public function canChangeProtectedData($value, array $context)
{
    \Cake\Log\Log::debug("canChangeProtectedData");
    // Find logged user, look at the new value, check if he is authorized to do that, return true/false
    return false;
}

我的 cakephp < 3,authcomponent="" 有一个不再可用的静态方法="" 'authcomponent::user()'。那么,我如何在="" cakephp="" 3="" 中做到这一点?="">

感谢您的任何回复。

编辑 - 添加更多细节

所以这里有更多的细节。如果是 REST API。我有实体的编辑功能。 “文章”实体。

这篇文章的所有者在名为“user_id”的列上有一个外键(这里没有什么特别的)。我的用户被组织成组,组中有一个组长。组长可以更改文章的所有者,但“基本”用户不能这样做(但他们可以编辑自己的文章)。管理员用户可以编辑所有内容。 因此编辑方法必须可用于任何经过身份验证的用户,但必须允许更改实体的“user_id”并根据情况进行检查(如果我是管理员是,如果我是领导者是只有当新 ID 是一个我的组,如果我是基本用户则否)。

我可以在 Controller 上执行此检查,但如果我希望在修改文章的代码中的任何地方检查此规则(使用不同于 ArticlesController 的“编辑”的另一种方法)。所以对我来说,Model 似乎是放置它的好地方?

最佳答案

认证与授权

  • 身份验证是指通过凭据识别用户,大多数情况下归结为“用户是否登录”。
  • 授权表示检查用户是否被允许执行特定操作

所以不要混淆这两者。

你不需要验证你想要应用程序规则

摘自本书:

Validation vs. Application Rules

The CakePHP ORM is unique in that it uses a two-layered approach to validation.

The first layer is validation. Validation rules are intended to operate in a stateless way. They are best leveraged to ensure that the shape, data types and format of data is correct.

The second layer is application rules. Application rules are best leveraged to check stateful properties of your entities. For example, validation rules could ensure that an email address is valid, while an application rule could ensure that the email address is unique.

您要实现的是复杂的应用程序逻辑,而不仅仅是简单的验证,因此最好的实现方式是作为应用程序规则。

我从我的一篇解释类似案例的文章中摘录了一段代码。我必须检查可以与模型相关联的语言(翻译)的限制。您可以在这里阅读整篇文章 http://florian-kraemer.net/2016/08/complex-application-rules-in-cakephp3/

<?php
namespace App\Model\Rule;

use Cake\Datasource\EntityInterface;
use Cake\ORM\TableRegistry;
use RuntimeException;

class ProfileLanguageLimitRule {

   /**
    * Performs the check
    *
    * @link http://php.net/manual/en/language.oop5.magic.php
    * @param \Cake\Datasource\EntityInterface $entity Entity.
    * @param array $options Options.
    * @return bool
    */
   public function __invoke(EntityInterface $entity, array $options) {
      if (!isset($entity->profile_constraint->amount_of_languages)) {
         if (!isset($entity->profile_constraint_id)) {
            throw new RuntimeException('Profile Constraint ID is missing!');
         }
         $languageLimit = $this->_getConstraintFromDB($entity);
      } else {
         $languageLimit = $entity->profile_constraint->amount_of_languages;
      }

      // Unlimited languages are represented by -1
      if ($languageLimit === -1) {
         return true;
      }

      // -1 Here because the language_id of the profiles table already counts as one language
      // So it's always -1 of the constraint value
      $count = count($entity->languages);
      return $count <= ($languageLimit - 1);
   }

   /**
    * Gets the limitation from the ProfileConstraints Table object.
    *
    * @param \Cake\Datasource\EntityInterface $entity Entity.
    * @return int
    */
   protected function _getConstraintFromDB(EntityInterface $entity) {
      $constraintsTable = TableRegistry::get('ProfileConstraints');
      $constraint = $constraintsTable->find()
         ->where([
            'id' => $entity['profile_constraint_id']
         ])
         ->select([
            'amount_of_languages'
         ])
         ->firstOrFail();

      return $constraint->amount_of_languages;
   }

}

我认为这是不言自明的。确保您的实体 user_id 字段对于“公众”是不可访问的。在保存数据之前,在修补之后添加它:

$entity->set('user_id', $this->Auth->user('id'));

如果您更改上述代码段并将 profile_constraint_id 更改为 user_id 或您拥有的任何其他内容,这应该可以为您完成工作。

您真正想要的是基于行/字段级别的授权

我想您可以为此使用 ACL,但我从来没有需要基于字段的 ACL。所以我不能给你太多的意见,但它是 (Cake2) 并且仍然是 (Cake3) 可能的。对于 Cake3,ACL 内容已移动 to a plugin .从技术上讲,可以检查任何内容、数据库字段、行等等。

您可以编写一个使用 Model.beforeMarshal 事件的行为,并检查 user_id(或角色,或其他)是否存在且不为空,然后检查您想要的所有字段使用 ACL 给定用户 ID 或用户角色。

您可能会使用 this method PermissionsTable::check()或者您可以编写一个更专用的方法同时检查多个对象(字段)。就像我说的,如果您愿意的话,您会花一些时间来找出使用 ACL 的最佳方法。

UX 和另一种廉价的解决方案

首先,我将显示所有字段,不允许用户更改或输入作为输入。如果您需要显示它们,很好,禁用表单输入或仅将其显示为文本。然后使用一组常规验证规则,要求该字段为空(或不存在)或清空基于您的用户角色的字段列表。如果您不显示这些字段,用户将不得不调整表单,然后也无法通过 CSRF 检查(如果使用)。

关于php - Cakephp 3 - 如何在验证过程中检索 'Table' 类中的当前登录用户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31783066/

有关php - Cakephp 3 - 如何在验证过程中检索 'Table' 类中的当前登录用户?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  9. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  10. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

随机推荐