I'm relatively new to Symfony 2 and I'm working on an application which has an admin only login area located under domain.com/admin/home/ (which itself is a separate bundle called AdminBundle) allowing the admin to manage products
However the same application is also going to have a BlogBundle which will require an admin area to manage blog posts.
What is the best way to tackle this, is there a best practice for multiple admin areas?
It makes sense to keep the blog admin section within the BlogBundle for better re-usability/portability, however all of the login settings will be in the AdminBundle which seems wrong.
One way to do this is to use your security.yml file to secure a set of routes. For example;
access_control:
...
- { path: ^/admin, roles: [ROLE_ADMIN] }
Then when you create your actions you simply need to give them a route with an admin prefix to secure them against all users other than admin. My examples use annotation for routing but you can do the same with yml.
/**
* Edit a Blog entity.
*
* #Route("/admin/blog/{id}/edit", name="blog_edit")
* #Template()
*/
public function editAction()
{
...
Or you could secure every action in the controller by prefixing the class:
/**
* AdminBlog controller.
*
* #Route("/admin/blog")
*/
class AdminBlogController extends Controller
{
...
Then create another controller which handles displaying the blog posts to the end user and give them unsecured routes.
If you want to secure other areas in seperate bundles your can do it in the same way by have secure and unsecure controllers/ methods.actions
Related
I have a web-app where every User has his own personalized link
https://app.myapp.com/{uuid}/frontpage
Where uuid indicates User resource loaded from the database.
And now, the idea is to move /{uuid}/ to subdomain, so it should look as follows:
https://{uuid}.myapp.com/frontpage
While I have created wildcard DNS and can extract subdomain in Symfony's Controllers easily, the problem is now how to tell Symfony that uuid should be taken from subdomain now.
In Controllers I have routing defined as follows
/**
* #Route("/{uuid}/frontpage", name="frontpage")
* #ParamConverter("user", class="AppBundle:User", converter="converter.user")
* #Template("FrontPage.html.twig")
*/
public function indexAction(Request $request, User $user)
{
}
I would like to avoid rewriting all Controllers and strip out /{uuid}/ part because I have hundreds of Controllers defined like that.
Is there a way to manage this maybe via Listeners?
With Symfony 3, you can match a route based on the host. And basically you can also "placeholderize" your subdomain and get the related value in your HttpFoundation\Request object (in your controller for instance).
Ex. :
mobile_homepage:
path: /
host: "{subdomain}.example.com"
defaults:
_controller: AppBundle:Main:mobileHomepage
subdomain: m
https://symfony.com/doc/current/routing/hostname_pattern.html
I need to set up several parameters after user authentication.
We have a db with with oauth2 clients.
When one of them got access token and is trying to get access to protected API I need to identify the client (which is easy since access_token is bound to particular client) and define several application parameters (actually I need to load a specific file parameters.yml depends on the client).
My questions is:
How can I hook to event when user is authenticated?
How can I load a particular parameters.yml and make it relevant after user authenticate ?
Thank you!
When user is successfully authenticated, you can write a listener which listens to SecurityAuthenticationEvents::AUTHENTICATION_SUCCESS.
The public method of the listener should look like this:
public function onAuthenticationSuccess(AuthenticationEvent $event)
{
/**
* #var User $user
*/
$user = $event->getAuthenticationToken()->getUser();
// ...
return;
}
I believe you can use YamlFileLoader for that. Of course you can create a service class to read the contents from yaml files and provide them to different services in your app. I would not try to mix them with regular parameter / config files.
Playing around with symfony. I have two bundles and each bundle has a controller within it. Just to see how routing works I gave the same path to functions within both controllers. Bundle B was the newly created bundle and when the URL app/simple was hit I got a response from bundle B always. Just curious as to whether there is any logic behind this.
PS: I know this is bad practice but just wanted to see how the guts of routing in works.
/**
* #Route("/app/simple", name="homepage")
*/
public function indexAction()
{
return new Response('Hello From bundle A!');
}
In bundle B
/**
* #Route("/app/simple", name="homepage")
*/
public function indexAction()
{
return new Response('Hello From bundle B!');
}
Your app has a single routing configuration which can include other configurations. Probably app/config/routing.yml.
That configuration file will include the routes for your bundles by using the resource key that can import routes from another routing.yml file or from annotations in a PHP controller.
The order of those will determine which route gets chosen since Symfony2 always uses the first matching route.
I need to find a user object in symfony2 based on the username or emailadres. This is not for loggin in, but for other actions on a user.
I can simply request the (Doctrine2) repository and call the method loadByUsername from the UserProviderInterface that is on my repository-class.
But the code that needs to do this will be used in multiple projects and I need it to be a bit more generic. The user class/table might be different or the users might come from a completely different type of provider.
Is there a way to find a user by username just like Symfony2 itself uses when logging in?
This way it will work no matter how the user providers are configured in security.yml.
Is there some service in Symfony2 I can use for this?
Is there a "user provider service" where I can call a method something like "loadUserByUsername" that will try each configured provider?
After some poking into the SecurityBundle of Symfony itself, I figured out the following:
Given this is in your security.yml:
providers:
AdministrationUser:
entity:
class: AdministrationBundle\Entity\User
Symfony will create a service with the following name:
security.user.provider.concrete.administrationuser
This service uses the UserProviderInterface and when you fetch this service you can simply call the method loadUserByName and find your user.
So all you need to know is the name of the provider you configured yourself and you can determine the service-name and fetch it.
I'm in a more generic situation, so I added an alias to that service in the Extension-class of my bundle:
// alias the user_provider mentioned
$container->setAlias('my_security_bundle.user.provider', new Alias('security.user.provider.concrete.' . strtolower($config['user']['provider'])));
Where $config['user']['provider'] comes from config.yml (and needs to be configured in your Configuration class, but that is a different story.
Now I can simply use that new alias and I will get the correct service to find my user in a Controller like so:
/** #var UserProviderInterface $userProvider */
$userProvider = $this->get('my_security_bundle.user.provider');
$user = $userProvider->loadUserByUsername('someone#somewhere.tld');
In a multi tenant web application should Symfony2 ACL framework be used for checking the ownership of domain objects?
I can't get the point since (assuming each table has a back reference to the User object) i can simply check current user id against the entity owner id, like the following:
/*
* #Route("/edit/{slug}")
* #Method("GET|POST")
* #Secure(roles="ROLE_USER")
* #Template
*/
public function editAction($slug);
{
// Find the post given the slug
$repo = $this->getDoctrine()->getRepository('AcmeHelloBundle:Post');
$entity = $repo->findOneBySlug($slug);
$current = $this->get('security.contex')->getToken()->getUser();
// 404 if slug is invalid
if(!$entity) throw new $this->createNotFoundException();
// AccessDenied if current user is not the owner of the entity
if($current->getId() != $entity->getUser()->getId())
throw new AccessDeniedException();
}
Maybe ACL can help avoiding back referencing each entity to the user table? Any explanation or example would be helpful, thanks.
ACL is useful when you have a scenario that multiple people have access to same domain. The ACL documentation has a good example for that.
For example, lets say you have SaaS providing collaborative document editing for companies. A company may want to restrict access to a document, to only allow the executives of the company to edit it and not the employees. In that scenario, you can't use the User token alone, since multiple members needs to access to the domain. This is where the usefulness of ACL comes in.