草庐IT

php - 选民导致 500 错误而不是 403

coder 2024-04-08 原文

我创建了一个自定义投票器,如果请求不包含有效的授权 header ,它会拒绝访问我的 API。它基于两个食谱条目的组合: http://symfony.com/doc/current/cookbook/security/voters.htmlhttp://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html

<?php

namespace Acme\RestBundle\Security\Authorization\Voter;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
use Monolog\Logger;

class ApiClientVoter implements VoterInterface
{
    protected $container;
    protected $nonceCacheDir;

    /**
     * We inject the full service container due to scope issues when
     * injecting the request.
     *
     * @param ContainerInterface $container
     * @param string $nonceCacheDir
     */
    public function __construct(ContainerInterface $container, $nonceCacheDir)
    {
        $this->container     = $container;
        $this->nonceCacheDir = $nonceCacheDir;
    }

    public function supportsAttribute($attribute)
    {
        // we won't check against a user attribute, so we return true
        return true;
    }

    public function supportsClass($class)
    {
        // our voter supports all type of token classes, so we return true
        return true;
    }

    public function vote(TokenInterface $token, $object, array $attributes)
    {
        if ($this->authenticate()) {
            return VoterInterface::ACCESS_ABSTAIN;
        }

        return VoterInterface::ACCESS_DENIED;
    }


    /**
     * Checks for an authentication header in the request and confirms
     * the client is valid.
     *
     * @return bool
     */
    protected function authenticate()
    {
        $request = $this->container->get('request');

        if ($request->headers->has('x-acme-auth')) {

            $authRegex = '/ApiKey="([^"]+)", ApiDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';

            if (preg_match($authRegex, $request->headers->get('x-acme-auth'), $matches)) {
                $apiClient = $this->container->get('in_memory_user_provider')->loadUserByUsername($matches[1]);

                if ($apiClient && $this->validateDigest($matches[2], $matches[3], $matches[4], $apiClient->getPassword())) {
                    return true;
                }
            }
        } else {
            $this->container->get('logger')->err('no x-acme-auth header present in request');
        }

        return false;
    }

    /**
     * Performs checks to prevent replay attacks and to validate
     * digest against a known client.
     *
     * @param string $digest
     * @param string $nonce
     * @param string $created
     * @param string $secret
     * @return bool
     * @throws AuthenticationException
     * @throws NonceExpiredException
     */
    protected function validateDigest($digest, $nonce, $created, $secret)
    {
        // Expire timestamp after 5 minutes
        if (time() - strtotime($created) > 300) {
            $this->container->get('logger')->err('Timestamp expired');

            return false;
        }

        if (!is_dir($this->nonceCacheDir)) {
            mkdir($this->nonceCacheDir, 0777, true);
        }

        // Validate nonce is unique within 5 minutes
        if (file_exists($this->nonceCacheDir.'/'.$nonce) && file_get_contents($this->nonceCacheDir.'/'.$nonce) + 300 > time()) {
            $this->container->get('logger')->err('Previously used nonce detected');

            return false;
        }

        file_put_contents($this->nonceCacheDir.'/'.$nonce, time());

        // Validate Secret
        $expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true));

        return $digest === $expected;
    }
}

我遇到的问题是,当我的选民返回 ACCESS_DENIED 时,当防火墙重定向到身份验证入口点时,我收到 500 错误:

[2012-10-05 11:09:16] app.ERROR: no x-acme-auth header present in request [] []
[2012-10-05 11:09:16] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\Security\Http\Firewall\ExceptionListener::onKernelException". [] []
[2012-10-05 11:09:16] security.DEBUG: Access is denied (user is not fully authenticated) by "/home/phil/projects/acme/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php" at line 70; redirecting to authentication entry point [] []
[2012-10-05 11:09:16] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelException". [] []
[2012-10-05 11:09:16] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ExceptionListener::onKernelException". [] []
[2012-10-05 11:09:16] request.CRITICAL: Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException: Full authentication is required to access this resource. (uncaught exception) at /home/phil/projects/acme/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php line 109

我实际上想要发生的只是返回 403 响应。可以这样做吗?

最佳答案

内核捕获的异常总是返回 HTTP 500。(code)。

如果身份验证无效,您必须返回自己的响应。

use Symfony\Component\HttpFoundation\Response;
$response = new Response();

$response->setContent('<html><body><h1>Bad Credentials</h1></body></html>');
$response->setStatusCode(403);
$response->headers->set('Content-Type', 'text/html');

// prints the HTTP headers followed by the content
$response->send();

关于php - 选民导致 500 错误而不是 403,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12749457/

有关php - 选民导致 500 错误而不是 403的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  4. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  5. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  6. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

  7. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  8. ruby-on-rails - 每次我尝试部署时,我都会得到 - (gcloud.preview.app.deploy) 错误响应 : [4] DEADLINE_EXCEEDED - 2

    我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie

  9. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  10. arrays - 这是 Ruby 中 Array.fill 方法的错误吗? - 2

    这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]

随机推荐