Chapters
36 Chapters
|
1:50:44
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: >=5.3.3
Subscribe to download the code!Compatible PHP versions: >=5.3.3
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
08.
Denying Access: AccessDeniedException
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=5.3.3",
"symfony/symfony": "~2.4", // v2.4.2
"doctrine/orm": "~2.2,>=2.2.3", // v2.4.2
"doctrine/doctrine-bundle": "~1.2", // v1.2.0
"twig/extensions": "~1.0", // v1.0.1
"symfony/assetic-bundle": "~2.3", // v2.3.0
"symfony/swiftmailer-bundle": "~2.3", // v2.3.5
"symfony/monolog-bundle": "~2.4", // v2.5.0
"sensio/distribution-bundle": "~2.3", // v2.3.4
"sensio/framework-extra-bundle": "~3.0", // v3.0.0
"sensio/generator-bundle": "~2.3", // v2.3.4
"incenteev/composer-parameter-handler": "~2.0", // v2.1.0
"doctrine/doctrine-fixtures-bundle": "~2.2.0", // v2.2.0
"ircmaxell/password-compat": "~1.0.3", // 1.0.3
"phpunit/phpunit": "~4.1" // 4.1.0
}
}
12 Comments
Hey Weaver!
Like always, great work on this tutorials.
I have a little problem with an automatic redirect by symfony. When I throw that AccessDeniedException to an anonymous user, besides of error page it gets a redirect to Login Page.
Is there a way to disable that redirect or something? I couldn't find a solution on documentation =/
Thanks in advance ;]
Hey Diego :)
Yes, this behavior is totally by design - it allows the user to get a chance to login to see a secured page. What's your use-case for *not* doing this?
Either way, the whole point of throwing AccessDeniedException is to "redirect to login if they're anonymous OR show them a 403 error page". If you don't want this, you're always free in a controller to simply return a Response object with a 403 status code (e.g. something like "return new Response("get outta here", 403)". Of course, that means you won't be using your *normal* Symfony 403 error page. If you try want to force a 403, but not do the redirect, throw an exception of the class Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException. If you want to know *why* that works, let me know ;).
Cheers!
Great! AccessDeniedHttpException was the key, I'm not getting redirected anymore.
Why is this working :)?
My reason is because my login form is inside an iframe, so I just can't do a redirect. What I need is to show a message saying "You need to login first" and a button which opens the iframe, if login is successful, then redirect to the desired page.
You can see what I want to achieve in my small site ( https://www.esla.pro ) just click where it says "Inicia Sesion" at the top section.
I'm translating the whole site to symfony2 :)
Thanks for your time.
Hi Diego!
For why is this working? There are two things happening:
1) AccessDeniedException is a very special exception. When you throw it, it triggers the part of Symfony that tries to get the user to login (usually by redirecting them to /login). Here's the internals for that: https://github.com/symfony/...
2) If you throw any Exception, it usually triggers a 500. BUT, that's not always true. If the Exception class you're throwing implements a special HttpExceptionInterface (https://github.com/symfony/..., then you will not get a 500, but whatever status code returned by that class's getStatusCode() method. The `AccessDeniedHttpException` is one of these: https://github.com/symfony/.... It causes a 403 status code, but doesn't trigger the special behavior in (1).
About your situation, here's my advice (fwiw):
1) Allow the user to be redirected to /login. This doesn't mean you need to eliminate your iframe popup (keep reading), but *also* allow for the login to be its own page (you could have /login basically be a blank page that has some JS to open your popup, if you really want to - it looks like you're doing something like this already: https://www.esla.pro/soport.... This will make your life much easier. One things Symfony already does is help redirect you back to the original page the user was trying to visit in this situation.
2) On a case-by-case basis, you can make some links automatically open your login popup. For example, when you render a page, if you could check to see if the user is not logged in (in Twig) and render a link to open the popup instead of, for example, taking the user to the registration page. OR, if a link does something with JavaScript, you could make the AJAX request, and if the user is not logged in, then open the popup.
If anything, the piece you need to override is called the "Entry Point" - this is the class that's called when Symfony says "the user is trying to access a protected resource, but they are not logged in, let's help them!". This is the class that causes the redirect - the default one is here: https://github.com/symfony/.... You may use want to use your own, to, for example, redirect on normal requests, but return a normal 403 on AJAX requests. You could extend the FormAuthenticationEntryPoint class, register your new class as a service, then put your service id on the entry_point key under your firewall: http://symfony.com/doc/curr...
Phew! That's a lot of info, but hopefully it's useful!
Cheers!
Wow, great answers, definitely it was useful!
I'll give it a try to use my own Entry Point (I hope it doesn't get too complicated).
Thanks for your time :)
Adding security checks in controller methods could quickly lead to massive code duplication.
Say that I have a few controllers with a few dozens of methods - the code will be almost unmaintainable.
So the question is: does Symphony have something like AOP to deal with cross cutting concerns?
Yo Ivan!
Very good point :). So there are a few things you can do:
1) You will want to keep your security checks very simple - basically one line. In this chapter, we're checking for a ROLE, which is a very simple check. So even if you need to duplicate it, you're basically duplicating one line (in fact, in the latest version of Symfony, it's literally one line:
$this->denyAccessUnlessGranted()). If your security logic is more complex (e.g. you need to check to see if the user is an admin, or if they are the "creator" of some Product to determine if they can edit it), then you'll want to use voters (http://knpuniversity.com/screencast/new-in-symfony3/voter) - this will centralize your logic.2) If you use voters well, then each controller will only need one line - some version of
$this->denyAcessUnlessGranted(...). To me, duplicating one line isn't really code duplication. However, you can do even a little bit better, by requiring a role for ALL actions in an entire class. This is done with the @Security annotation - http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html. The examples don't show it (but the docs do mention it): you can put the annotation above your controller class to apply it to all action methods.Besides that, you can always use
access_controlin security.yml, but that has limited flexibility. And to answer your question directly - there is nothing in Symfony specifically for AOP.Cheers!
Oh, it's interesting, I'll check that voters and controller security annotations. Thanks.
I also found a third way. It's an event system which seems to be the very flexible and looks somewhat like AOP:
http://symfony.com/doc/curr...
Hi great tuto,
Missing ";" in
function enforceUserSecurity()
Doh! Fixed it at sha: https://github.com/knpunive...
Thanks!
How is "throw $this->createAccessDeniedException('message!');" a SHORTCUT to "throw new AccessDeniedException('message!')" ? I mean... come on :P .
Haha :). Yes, but with the AccessDeniedException, you need to add a use statement! That's why :) (and there are 2 AccessDeniedException's in Symfony, which makes it a bit tricky for beginners).
"Houston: no signs of life"
Start the conversation!