FosrestBundle: إرجاع بيانات META JSON/XML لـ "بيانات الاعتماد السيئة"

StackOverflow https://stackoverflow.com/questions/19836178

سؤال

أنا أستخدم fosrestbundle لصالح API الخاص بي ، وحتى الآن كانت أداة رائعة. أستخدم HTTP Basic Auth وفي معظم الحالات تعمل بشكل جيد. ومع ذلك ، لدي مشاكل في سلوك استثناء الحزمة عند تقديم بيانات الاعتماد السيئة. عند التعامل مع الاستثناءات (عبر معالجات المصادقة المتكاملة أو تكوين رسم خرائط الاستثناء) ، تعطيني الحزمة دائمًا استجابة مع حالة HTTP الصحيح ومحتوى JSON/XML مماثل لهذا:

{
   "code": 401,
   "message": "You are not authenticated"
}

هذا جيد ، إنه يعمل أيضًا عندما لا مصادقة يتم تقديم المعلومات على الإطلاق. ومع ذلك ، عند التقديم أوراق سيئة (على سبيل المثال اسم مستخدم غير معروف أو كلمة مرور غير صحيحة) أحصل على بيانات اعتماد HTTP 401 السيئة (وهو أمر جيد) مع هيئة رسالة فارغة. بدلاً من ذلك ، كنت أتوقع شيئًا مشابهًا لـ JSON أعلاه.

هل هي مشكلة أو مشكلة تكوين من جانبي؟ أحب أيضًا أن أعرف كيف تتم معالجة هذه الأنواع من أخطاء المصادقة تمامًا من قبل الحزمة ، لأن التغلب على BadCredentialsExceptionرمز الحالة في codes يبدو أن قسم تكوين استثناء الحزمة يتم تجاهله.

شكرًا!

هل كانت مفيدة؟

المحلول

حسنًا ، بعد البحث في رمز الحزمة ، اكتشفت ذلك. تنتج المشكلة عن الطريقة التي يتم بها التعامل مع أوراق الاعتماد السيئة من خلال الفكين المصادقة الأساسي لـ Symfony HTTP. ال 401 Bad Credentials الاستجابة هي استجابة مخصصة تم إنشاؤها بواسطة BasicAuthenticationEntryPoint, التي تسمى من قبل BasicAuthenticationListenerhandle وظيفة ، مباشرة بعد AuthenticationException تم إلقاؤه في نفس الوظيفة. لذلك لا توجد طريقة لالتقاط هذا الاستثناء مع المستمع:

public function handle(GetResponseEvent $event)
{
    $request = $event->getRequest();

    if (false === $username = $request->headers->get('PHP_AUTH_USER', false)) {
        return;
    }

    if (null !== $token = $this->securityContext->getToken()) {
        if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) {
            return;
        }
    }

    if (null !== $this->logger) {
        $this->logger->info(sprintf('Basic Authentication Authorization header found for user "%s"', $username));
    }

    try {
        $token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
        $this->securityContext->setToken($token);
    } catch (AuthenticationException $failed) {
        $this->securityContext->setToken(null);

        if (null !== $this->logger) {
            $this->logger->info(sprintf('Authentication request failed for user "%s": %s', $username, $failed->getMessage()));
        }

        if ($this->ignoreFailure) {
            return;
        }

        $event->setResponse($this->authenticationEntryPoint->start($request, $failed));
    }
}

نقطة الدخول start تعمل الوظيفة على إنشاء استجابة مخصصة ، مع عدم وجود استثناءات:

public function start(Request $request, AuthenticationException $authException = null)
{
    $response = new Response();
    $response->headers->set('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realmName));
    $response->setStatusCode(401, $authException ? $authException->getMessage() : null);

    return $response;
}

القبضة if-رصفة في handle تشرح الوظيفة أعلاه أيضًا سبب عملها في حالة "عدم وجود بيانات اعتماد مستخدم على الإطلاق" ، لأنه في هذه الحالة ، يتوقف المستمع فقط عن محاولة مصادقة المستخدم ، وبالتالي سيتم إلقاؤه استثناء من قبل مستمعي جدار الحماية في Symfony (ليس متأكدًا تمامًا من أين بالضبط) ، حتى fosrestbundle AccessDeniedListener قادر على التقاط AuthenticationException ويفعل الشيء.

نصائح أخرى

يمكنك تمديد AccessDeniEniedListener وأخبر FosrestBundle لاستخدام المستمع الخاص بك مع المعلمة %fos_rest.access_denied_listener.class%. (تعريف الخدمة)

parameters:
    fos_rest.access_denied_listener.class: Your\Namespace\For\AccessDeniedListener

ثم أضف شيكًا إضافيًا لـ BadCredentialsException و emmit an HttpException مع الرمز/الرسالة المطلوبة على غرار التحقق من AuthenticationException في الخط 70.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top