Creating a Custom Voter
…s a maker for that! Over in your terminal, run:
symfony console make:voter
Call it StarshipVoter.
Now go take a look at what that created: src/Security/Voter/StarshipVoter.php.
It added some boilerplate for us, including two permission constants. For the first
one…
Fetching the User in Services/Controllers
…You may need to access the
current user in another service. And that service won't have access to the AbstractController
helper methods.
In our index() method, inject Security, the one from the SecurityBundle, $security:
This is a helper service that can access the currently…
Impersonating Users with switch_user
…without
that role cannot switch users.
Finally, target_route is where you want to send the user after the switch occurs.
Time to configure this. First, go to config/packages/security.yaml. Down in role_hierarchy, under
ROLE_ADMIN, add ROLE_ALLOWED_TO_SWITCH:
Now…
Role Hierarchy & Access Control
…roles. So add ROLE_CAPTAIN as a child:
Now refresh the /parts page... Nice! We have access!
If you open the security profiler panel you can see, yep, her roles are ROLE_ADMIN and
ROLE_USER. But there's a new section below: "Inherited Roles"…
Protecting Logout with CSRF
…request, doesn't mean other sites can't
trigger it. To completely prevent this, we need to implement CSRF protection for it.
Open config/packages/security.yaml. Under the main firewall section, find the logout key.
Add enable_csrf: true:
Let's try it out…
app.user and Login/Logout Links
…accepts a $key
parameter, which is the firewall key defined in config/packages/security.yaml under the firewalls section.
Passing a key allows generating logout links for different firewalls.
There's another common method to check if a user is logged in. Our users have…
Enabling "Remember Me" Feature
…tweak this cookie to your liking. To see the options,
run the following in your terminal:
symfony console config:dump framework session
Remember, the session isn't security-specific, that's why it's configured at
the framework level.
Here, you can see that we…
User Roles
…just like isGranted(), is another helper that comes from AbstractController.
It throws the correct exception, which will be caught by Symfony's security system and handled
appropriately.
Hope over to the app in your browser and refresh the /parts page. Huh. We're redirected to…
User API Resource
…user or updating their password. Then we will hash it. That's
something we're going to solve in a future tutorial when we talk more about security.
But this will be good enough for now.
Oh, and above username, also add user:read and…
Logout & Passing API Data to JavaScript
…to throw an exception from
inside the method. We've created this entirely because we need a route:
Symfony's security system will intercept things before the controller is called:
To activate that magic, in security.yaml, add a key called logout with path
below…
API Login Form with json_login
…email & password,
head to config/packages/security.yaml. Under the firewall, add json_login and
below that check_path... which should be set to the name of the route that we
just created. So, app_login:
This activates a security listener: it's a bit…
Handling Authentication Errors
…AJAX call is working great. Though, there is one gotcha with the json_login
security mechanism: it requires you to send a Content-Type header set to
application/json. We are setting this on our Ajax call and you should
to:
But... if someone forgets…
API Tokens? Session Cookies?
…how the end-user will get that token.
So let's talk about that first use-case: the user of your API is your own JavaScript.
Well, before we even dive into security, make sure your frontend and your API live
on the same domain..…
Admin Dashboard
…you want to, instead of using the IsGranted PHP attribute, you
could also say $this->denyAccessUnlessGranted(). And you could also go to
config/packages/security.yaml and, down at the bottom, add an access_control
that protects the entire /admin section:
Actually, adding this access…
Bonus: Messenger Monitor Bundle
…to access the UI as it
shows sensitive information. We don't have security configured in this app,
so I'll just remove this line:
src/Entity/ProcessedMessage.php is a new entity added by the recipe. This is
also a stub that extends this…
User Test + Plain Password
…The user
sends the plain-text password they want... then we're saving that directly into
the database. That's a huge security problem... and it makes it impossible to
log in as this user, because Symfony expects the password property to hold a
hashed…
Conditional Fields by User: ApiProperty
…but then this would override that. Watch: if we try the tests:
They pass because the field is gone.
For our mission, we can leverage a super cool option called security. Set it
to is_granted("ROLE_ADMIN"):
That's it! If this expression return…
Allow Admin Users to Edit any Treasure
… Well, at first, it's relatively
easy because we have total control via the security expression. So we can add
something like if is_granted("ROLE_ADMIN") OR and then put parentheses around the
other use-case:
Let's make sure it works!
A 500…
Testing Authentication
…a faster way to log in. Instead of making the POST
request, say ->actingAs($user):
This is a sneaky way of taking the User object and pushing it directly into
Symfony's security system without making any requests. It's easier, and faster.
And now…
Totally Custom Fields
…to the data that they are not allowed to make - like they could set a field to
foo but they aren't allowed to change it to bar because they don't have enough
permissions. How should we handle that? It's security meets validation.
x
1000+