Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

The All-Important User Class

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Yo guys! You finally made it to the security course: you brave, brave souls. Whatever, these days, security isn't scary - it's super fun! You've got traditional login forms, Facebook authentication, GitHub authentication, and API authentication with JSON web tokens, just to name a few. When you're doing something with security these days, it's usually pretty darn fun. And we're going to learn enough so that you can implement whatever crazy, insane security system you want.

But, the only way to secure your new security skills it to feel secure in my recommendation that you code along with me. You guys know the drill: download the course code unzip it and look for the start/ directory. That'll have the same code that I have here. Open up the README file to find all the setup details. At the end, you'll open up a new tab and run:

./bin/console server:run

to start the built-in web server.

Authentication vs Authorization (Fight!)

Aquanauts assemble... to talk about security!

Security has two big parts. The first is authentication - this is all about who you are - and we'll cover it first. Authentication is the tough stuff, and there's a lot of variation - login forms, social media auth, API stuff - you get it.

The second big piece is authorization, and this doesn't care about who you are, just whether or not you have fins. I mean, whether or not you have permission to take an action. Authorization comes later.

What about FOSUserBundle?

Before swim there, let's talk about a super-famous bundle: FOSUserBundle. You might be wondering, should I use this? What does it do? Or, did I turn the oven off?

First, we will not use this bundle, but it is great and you did turn the oven off... probably.

It gives you a lot of free features that we will build by hand. But FOSUserBundle does not give you any special "security" system - it's much less interesting than that, in a good way! The bundle gives you just two things:

  1. A User entity in case you need to store users in the database
  2. A bunch of routes and controllers

for things like your login form, registration and reset password. Those are all things you can easily build yourself... but if you need them, why not use the bundle?

Anyways, we won't use it, and that'll be the best path to learn how the security system works. But when you finish, you might save yourself some time using FOSUserBundle.

Create that User Class

Now, back to authentication. Here's our first goal: create a login form where the user can sign in with their email and password. In this app, we'll load user info from the database.

No matter how your users will authenticate, the first step is always the same: create a User class.

In your Entity directory - create a new class called User. The only rule is that this must implement a UserInterface. Add that:

... lines 1 - 2
namespace AppBundle\Entity;
... lines 4 - 5
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
... lines 10 - 28
}

I'll use Command+N - or the "Code"->"Generate" menu - and select "Implement Methods". Select all the new methods:

... lines 1 - 2
namespace AppBundle\Entity;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface
{
public function getUsername()
{
}
public function getRoles()
{
}
public function getPassword()
{
}
public function getSalt()
{
}
public function eraseCredentials()
{
}
}

Oh, and let's move getUsername() to the top: it makes more sense up there.

Is User an Entity?

Notice I did put my User class inside of the Entity directory because eventually we will store users in the database. But, that's not required: sometimes user details are stored somewhere else - like a central authentication server. In those cases, you will still have a User class, you just won't store it with Doctrine.

More on that as we go along.

Ok, we've got the empty user class: let's fill it in!

Leave a comment!

18
Login or Register to join the conversation
Apr Avatar

Hello again, and thank you very much for your tutorials.
I followed this authentication system and I got an error I can't solve. If I update my roles or the roles from another user and I don't logout and log in again the app get crazy remembering somehow the old roles. I leave the link from stackoverflow here.

https://stackoverflow.com/q...

Thank you very much for advance.

Reply
MolloKhan Avatar MolloKhan | SFCASTS | Apr | posted 5 years ago | edited

Hey Apr

Nice question! I had to do some research ;)

Look's like that's a feature that haven't been finished yet https://github.com/symfony/...
but there is a workaround - manually refreshing the user-token via subscriber. For more details about how the code looks like check this thread https://github.com/symfony/...

Cheers!

Reply
Default user avatar
Default user avatar Terry Caliendo | posted 5 years ago

Just curious what software you use to make such great animations lika at the beginning of this video?

Reply

Yo Terry! We do this right inside Screenflow, our screen-recording/video-editing software. The magic is mostly worked by Leanna - she's gotten pretty good at this stuff over the years :)

Reply
Mike P. Avatar
Mike P. Avatar Mike P. | posted 5 years ago

PHPStorm doesn't autogenerate the use statement for "Symfony\Component\Security\Core\Role\Role" (SF 3.3.6). In the video it seems that oh-storm is generating it while we implement all methods. Do you know why? Is this necessary?

Reply

Yo Mike P.!

The Role use statement is totally unnecessary - don't worry about it :). I believe it is added because the PHPDoc above the getRoles() method mentions it. I'm not sure why it would not generate now... but it's definitely not needed. Good eye ;)

Cheers!

1 Reply
Default user avatar

Hello!

So I downloaded the course, and replaced my old code with this start code. Now I cannot get into the server... Think you can help?

Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "KnpMarkdownBundle" from namespace "Knp\Bundle\MarkdownBundle".
Did you forget a "use" statement for another namespace? in /Users/Brian/aqua_note/app/AppKernel.php:19

Stack trace:
#0 /Users/Brian/aqua_note/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(406): AppKernel->registerBundles()
#1 /Users/Brian/aqua_note/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(113): Symfony\Component\HttpKernel\Kernel->initializeBundles()
#2 /Users/Brian/aqua_note/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(68): Symfony\Component\HttpKernel\Kernel->boot()
#3 /Users/Brian/aqua_note/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(121): Symfony\Bundle\FrameworkBundle\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))

#4 /Users/Brian/Glamp in /Users/Brian/aqua_note/app/AppKernel.php on line 19

Thank you :)

Reply

Hey Brian!

I think you forgot to run
$ composer install
If that's not the case, something might went wrong when replacing old files, try deleting the current project and unzipping again the downloaded project

Cheers!

Reply
Default user avatar
Default user avatar Mike Ritter | posted 5 years ago

cookies? ice cream? i'm hungry.

Reply

haha that's funny ;)

Reply
Default user avatar
Default user avatar Kasia Tychańska | posted 5 years ago

Hello,
could you please help me? When I try to open downloaded files I get this error.
What should I do?

Warning: require_once(C:\xampp\www\school\vendor/composer/autoload_real.php): f
iled to open stream: No such file or directory in C:\xampp\www\school\vendor\au
oload.php on line 5
PHP Fatal error: require_once(): Failed opening required 'C:\xampp\www\school\
endor/composer/autoload_real.php' (include_path='C:\xampp\php\PEAR') in C:\xamp
\www\school\vendor\autoload.php on line 5

Fatal error: require_once(): Failed opening required 'C:\xampp\www\school\vendo
/composer/autoload_real.php' (include_path='C:\xampp\php\PEAR') in C:\xampp\www
school\vendor\autoload.php on line 5

Reply

Hey Kasia Tychańska

I believe you forgot to run
$ composer install

Try that, and tell me what happened. Also, there is a README.txt file with more installation instructions

Cheers!

Reply
Default user avatar

Hello
Please, explain me.
When I use cmd I write for example
php bin/console server:run
In your course write
./bin/console server:run

Why such difference?
Why your don't need write php forward bin/console server:run

May be, I need to read something to understand this?

Reply

Hey Nina,

Actually, it's the same... but there's a subtle difference. The more expanded example is:

"php ./bin/console server:run"

That's because Symfony console (which is ./bin/console) is written in PHP, i.e. you can open ./bin/console file with PhpStorm or other editor and you'll find a PHP code there. So to run PHP code we need a PHP interpreter, i.e. call php at first and then pass it a file as an argument: "php ./bin/console". But Linux based OS like Ubuntu, Mac OS, etc. allow you to skip it and execute this file directly, but to get it working you need this file has execution permissions. It means that on some OS your can skip PHP prefix and execute this command directly like just "./bin/console", but if it doesn't work and you have an error that the file can't be executed - you can always run this file through PHP interpreter like: "php ./bin/console". If you're on Windows, most probably you need to use this expanded example. Otherwise, try the short one first. If it works - great, use it! If not, just fallback to the expanded syntax. Ryan records screencasts on a Mac, that's why on the video you can often see the short example, but we try to use expanded example in our course scripts.

Cheers!

Reply
Default user avatar

Could I give access to this file execution permissions on Windows?

Reply
Jelle S. Avatar
Jelle S. Avatar Jelle S. | posted 5 years ago

When I start the built-in server I get the error:

[ERROR] This command needs the pcntl extension to run.

You can either install it or use the "server:run" command instead to run the built-in web server.

I can still start the server with "y" but I'm curious why the error appears?

Reply

Yo Jelle S.!

Great question! There are two ways to start the built-in server: server:start and server:run. The only difference between the two is that server:run "blocks" your terminal afterwards - i.e. you can't type anything in that terminal anymore until you type "ctrl+c", which kills the server. However, when you use server:start, it starts a background process and returns your terminal to you. Later, you can run server:stop to kill that background process. But, this little dance requires the pcntl extension :). I think when you're typing "y", it's just falling back to using server:run

We show server:run only in our tutorials because (A) it works for everyone and (B) sometimes you can forget you have a server started, then try to start one later and get an error. In other words, the behavior of server:run causes less surprises :).

Cheers!

2 Reply
Jelle S. Avatar

Thanks, Ryan, I'll be using server:run from now on ;)

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}
userVoice