Symfony security mechanism

Source: Internet
Author: User
Tags class definition serialization

In previous factory methods, a large number of factory classes have increased the complexity of call dependencies between classes, and developers often have to deal with this dependency, and as the factory class grows, it is inevitable that this dependency process will inadvertently result in some errors. In addition, in unit tests, because the specific functional units are encapsulated within each factory class, we need to drill down into the inside of the class to test, and if there are parts of these functional units that depend on other classes, we will need to modify them and restore them after the test is completed.

Since the factory class is the base Class library role, the customized business functions need to be stripped out of the concrete factory classes, but still retain the common processing process. It is also said that the dependencies between the underlying classes are stripped out. The pattern of the application-tier class that relied on the underlying underlying classes in our previous development was reversed, becoming the base class dependent on the application-tier class, which means that dependencies have been reversed, known as "control reversal" (IOC, inversion Ofcontrol).

The callback mechanism that we often use is an embodiment of IOC thought. For example, the Windows system for the control of the message mechanism, the reception of messages, judgments, triggers and other work by the system itself, for the specific process of message processing by the user to decide, we can through the event subscriber for each control set specific processing methods.

The Framework abstracts the general process and encapsulates the mature and stable process. For developers, custom code can be implanted into specific processes through the specification provided by the framework (such as subclass abstract classes or implementation of related interfaces, and implementation of relevant interface protocols and interfaces) to achieve customized requirements under specific scenarios.

Dependency Injection (Di,dependency injection) is a specific way to realize the principle of control reversal, that is, to realize the dependency relationship through injection, and the framework can call the specific processing method according to the injected parameters when the operation is processed to the corresponding position. Symfony has done a good job of relying on injection, and the entire framework of code is implemented in this way. Below we mainly explain the implementation process of security in Symfony.

Symfony's security system is powerful beyond your imagination, but its configuration is also easy to create confusion. Here's a step-by-step tutorial on how to set up in your application, from configuring the firewall to how to load users to deny access and get user objects, depending on what you need to do, and sometimes just having to do some simple initialization settings, and once that's done, Symfony's security system will work very flexibly and efficiently. The main steps are as follows: 1.1 initialize SECURITY.YML Setup (authentication)

The file to be configured for the security system is: APP/CONFIG/SECURITY.YML. The general default configuration is as follows:

#app/config/security.yml Security
:
providers:
custom_provider:
        in_memory:
            Memory: ~
Firewalls:
    Dev: pattern
        : ^/(_ (PROFILER|WDT) |css|images|js)
        security:false
    default:
        Aynonymous: ~

The key word "firewalls" is the security configuration core, the Firewalls configuration keyword "dev" is not necessary, The main purpose is to ensure that Symfony's developer tools are not blocked by the security system.

Firewalls the default configuration entry filters all URL requests (if no pattern is set to imply that all URL strings will be matched) keyword aynonymous Care is the URL of the authentication problem. Now open the home page in developer mode, and you can see that you are currently using anon. authenticated, which means you are just an anonymous user. As shown in the following illustration:

A detailed description of how to filter the identified URL or controller is described later.

Security is highly configurable, and the options and their explanations are described in detail in the Security configuration reference. 1.1.1 Configuration uses your user for authentication

The role of the firewall firewalls is to configure how to authenticate using your user, using the login form (login forms). Or the Basic authentication provided using the HTTP protocol. Or use an API token. or above all the way.

First, we use the HTTP protocol to provide the basic authentication. Activate by adding Http_basic to the Firewalls configuration item:

#app/config/security.yml Security
:
#

... Firewalls:
    #
    ... Default:
        aynonymous: ~
http_basic: ~

It's so simple, try to do it. You will see a page that requires you to enter a username and password to log in. To make it more interesting, we can create a page with a URL of /admin . In the following example, if you are using the annotations method, you can write this:

src/appbundle/controller/defaultcontroller.php
//...
Use Sensio\bundle\frameworkextrabundle\configuration\route;
Use Symfony\bundle\frameworkbundle\controller\controller;
Use Symfony\component\httpfoundation\response;
Class Defaultcontroller extends Controller
{
/**
* @Route ("/admin") */public
function Adminaction ()
{return
new Response (' 

Next, add the access_control entry in the "security.yml" configuration file to require the user to log on while accessing the /admin page.

# app/config/security.yml Security
:
#
... Firewalls:
#
... Default:
#
... Access_control:
# require role_admin for/admin*
-{path: ^/admin, roles:role_admin}

Now that you have access to the /admin page, you will see the HTTP Basic Authentication dialog box:


But the question is, what do you want to use to log in. Where the user comes from. 1.1.2 Configuration Use your user to log in

When you enter a username in the dialog box, Symfony needs to load your user information from a "user provider", as well as configure it. Symfony built a way to load users from a database, or you can create your own "Userprovider".

The easiest way (usually limited) is to configure Symfony to obtain hard-coded users from its own "security.yml". This is called an "in memory" driver provider, but the best way is to create an "in Configuration" driver provider:

# app/config/security.yml Security
:
providers:
in_memory:
Memory:
users:
Ryan:
Password:ryanpass
roles: ' Role_user '
admin:
password:kitten
roles: ' Role_admin '
# ...

Like firewalls , you can have multiple drive providers, but you can only use one of them. If you have multiple, you can specify a driver provider (for example,provider:in_memory) to use in the provider keyword in the firewall firewall.

Try to log in using the username "admin" password "kitten" and you will see an error.

To correct this error, add a encoders keyword:

# app/config/security.yml Security
:
#
... Encoders:
symfony\component\security\core\user\user:plaintext
...

User-driven providers is used to load user information and put it into a user object UserObject. If you are loading a user through a database or other data source, you need to create your own user class to complete the process. However, when you use the "InMemory" Driver, a user class is built into the system to implement this process: "symfony\component\security\core\user\userobject".

Whatever your user class is, you need to tell symfony the encryption algorithm used to encrypt the user's password. In this case, the password is in plaintext. But next, you can use the bcrypt encryption algorithm.

Now refresh and you'll be able to complete the login. The debug toolbar in the browser page will even tell you who you are and what role you are currently using.

Because the URL requires the role to be role_admin, if you are logged in with a Ryan user, the system will reject your access request.

load users from a database

There are two main steps: one is to create your user entity, and the other is to configure "security.yml" to load the system from your user entity.

① Create the user entity

Suppose you have a User entity in your Appbundle that contains these fields:id,username, password, email and isactive.

src/appbundle/entity/user.php namespace Appbundle\entity;
Use doctrine\orm\mapping as ORM;
Use Symfony\component\security\core\user\userinterface; /** * @ORM \table (name= "app_users") * @ORM \entity (repositoryclass= "appbundle\entity\userrepository") * */Class User Implements UserInterface, \serializable {/** * @ORM \column (type= "integer") * @ORM \id * @ORM \generatedvalue (strategy= "
AUTO ") * * private $id;
/** * @ORM \column (type= "string", length=25, unique=true) * * Private $username;
/** * @ORM \column (type= "string", length=64) * * Private $password;
/** * @ORM \column (type= "string", length=60, unique=true) * * Private $email;
/** * @ORM \column (name= "is_active", Type= "boolean") * * private $isActive; The Public Function __construct () {$this->isactive = true;//May is not needed, the ' I ' on salt below//$this->sa
LT = MD5 (uniqid (NULL, true)); The Public Function GetUserName () {return $this->username;} public Function GetSalt () {//your *may* need a real salt dep Ending on your encoder//The "below" on salt is return null; Public Function GetPassword () {return $this->password;} public Function GetRoles () {return array (' Role_user '); pub Lic function Erasecredentials () {}/** @see \serializable::serialize () */Public Function serialize () {return serialize (AR
Ray ($this->id, $this->username, $this->password,//The section on salt below//$this->salt,)); /** @see \serializable::unserialize () */Public Function unserialize ($serialized) {list ($this->id, $this->usern
Ame, $this->password,//* The section on salt below//$this->salt) = Unserialize ($serialized);
 }
}

For simplicity, some accessor getter and setter methods are omitted. You can create this in the following ways:

$ php bin/console doctrine:generate:entities appbundle/entity/user

Next, make sure that the corresponding datasheet is also created successfully:

$ php bin/console Doctrine:schema:update–force

What is the user interface UserInterface?

So far, we've just created a normal data entity, but to use this class in the security system, you need to implement UserInterface, and you have to enforce the following 5 methods:

GetRoles ()

GetPassword ()

GetSalt ()

GetUserName ()

Erasecredentials ()

what the serialization and deserialization methods do.

After the end of a request, the user object is serialized and saved to the session, and the next request is deserialized when it arrives. In order for PHP to do this correctly, you need to implement the Serialize method yourself, but it's not all serialization, just the fields you need. In each request, the user information is queried from the database through the ID field and the user object is refreshed

② Configure security to load from your user entity

Now that you have a user entity that implements the UserInterface, you only need to tell Symfony's security system in the "security.yml" file. In this example, the user enters their username and password through the HTTP Basic Authentication window, Symfony queries the user entity, matches the username, and verifies the password:

# app/config/security.yml Security
:
encoders:
appbundle\entity\user:
algorithm:bcrypt
# ...
providers:
our_db_provider:
entity:
class:AppBundle:User
property:username
# if You ' re using the multiple entity Managers
# Manager_name:customer
firewalls:
main: Pattern
: ^/
Http_basic: ~
provider:our_db_provider
# ...

First, theencoders configuration item tells Symfony to use the bcrypt encryption algorithm for the user password in the database. Second, the providers configuration item creates a user driver called Our_db_provider , which tells the system to pass username from appbundle:user Entity to query. Our_db_provider naming is not important and only needs to be consistent with the key values of provider in firewall. Alive you don't have to set the provider key value, the system will automatically use the first user-driven.

Create a user record in the database.

When to set the Salt property. All passwords are hashed using a salt. If you use the Bcrypt algorithm for encryption, it is already implemented internally, and the GetSalt () method inUser returns null(that is, not used). If you use a different encryption algorithm, then you need to add a long salt attribute.

disables inactive users. If a user IsActive property is false(the field value in the database is 0), the user can still log on normally. To exclude inactive users, you need to modify the user class to implement the Advanceduerinterface interface, which extends from userinterface.

Add a Login form page to replace the authentication mechanism for the HTTP protocol. 1.1.3 Encrypt user password

Whether your users are stored in "security.yml" files, or stored in a database or somewhere else, the best encryption algorithm is bcrypt:

# app/config/security.yml Security
:
#
... Encoders:
symfony\component\security\core\user\user:
algorithm:bcrypt
cost:12

Now, your user password needs to be encoded using the actual encryption algorithm, and for hard coded users, you can use the commands you're building:

$ php bin/console Security:encode-password

It will produce the following things:

# app/config/security.yml Security
:
providers:
in_memory:
Memory:
users:
Ryan:
Password: $2a$12$lcy0mefviec3typhv9snnuzofyr2p/axigoqjeds4am4jwhnz/jli
roles: ' Role_user '
admin:
Password: $2a$12$cytwee9kpq1pjqkfiwuzfucrpwvyazwm4xzmz1qpufl7/flcm3v0g
roles: ' Role_admin '
...

The next job is the same as before. If you are using a dynamic user (such as a user from a database). How to encrypt user passwords programmatically before the user information is inserted into the database. Take a look at the details of the dynamic encryption password. 1.1.4 configuration complete

Congratulations, you now have a Basic authentication using HTTP, load the user's authentication system from the "security.yml" file, and the next task depends on your specific settings:

Configure a different way for the user to log on, such as a login form or any other way of making it completely customized.

Load users from different data sources, such as from a database or other data source.

Learn how to deny access, load user objects, and process authenticated roles. 1.2 Access denied, roles and other certifications

Users can now log on using HTTP Basic authentication mechanisms or other methods. Well, you now need to learn how to deny access and interact with user objects, which is called authentication. Its work determines whether a user can access some resources (URLs, models, methods, and so on).

The process of certification includes two main aspects:

① users receive a clear set of user roles when they log in;

② Add code (URL, controller) to indicate the properties that are available for access (typically Role_admin).

role

When a user logs on, the system automatically gets a collection of user role information, which is stored in a hard-coded manner in the "security.yml" file in the example above. If you are a user loaded from a database, the information is stored in a column in the table.

Note: All specified user roles must be prefixed with "role_", otherwise the Symfony security system will not be handled properly.

The character is very simple, is the basic string. Suppose you need to restrict access to the blog management features of your site, you can use the "role_blog_admin" role.

Note: Make sure that each user has at least one role, otherwise your users will not be able to pass validation, and the usual practice is to assign role_user roles to each user.

to add a code that denies access

There are two main ways to do this:

① is simpler but lacks flexibility by configuring Access_control in Security.yml files.

② is controlled by adding code to the Security.authorization_checker service. 1.3 Customizing your own user Provider

Symfony authentication mechanism processing relies on "userProvider", when the user submits a username and password is, the authentication layer requests a user object with username to the configured user driver (username Provider). Symfony then checks to see if the user's password is correct and generates a token for maintaining the authentication status in the current session. In addition, Symfony also has "in_memory" and "entity" user-driven. If your users are provided through a database, file, etc, then it is necessary to create your own user Provider. 1.3.1 Create the user class

Regardless of where your user data comes from, you create a user class first. No matter what the user class you want or what data it contains, the only requirement is to achieve userinterface. These requirements include the following methods in the user class definition: getroles (), GetPassword (), GetSalt (), GetUserName (), Erasecredentials (). It is also useful to implement Equaltableinterface, which defines a method by which a user checks whether a user is currently logged on to a user, or Isequalto ().

Class CurrentUser implements Advancedinterface, equaltableinterface{
private $username;
Private $password;
Private $salt;
Private $roles;

Public function SetData (array $user) {} public
function GetRoles () {} public
function GetPassword (
) {} Public Function GetSalt () {} public Function GetUserName () {} public Function
erasecredentials () {}
Public function Isequalto (UserInterface $user) {}
}
1.3.1 Create Userprovider class

With the user class (CurrentUser in the previous example code), you can create a user Provider to obtain information from a Web service such as UserService. The User provider class must implement the Userproviderinterface interface, which includes three methods: Loaduserbyusername ($username), Refreshuser (UserInterface $user ) and SupportClass ($class). For more details, please refer to userproviderinterface. Here's an example:

Class Userprovider implements userproviderinterface{public
function Loaduserbyusername ($username) {
    // Call you custom about the user's service, get user data
$user = $this->getuserservice ()->getuserbyloginfield ($username);
Pretend it returns an array on success
if (empty ($user)) {
    throw new usernamenotfoundexception (...);
}
$currentUser = new CurrentUser ();
$currentUser->setdata ($user);
return $currentUser;
}
Public Function Refreshuser (userinterface) {}
}
}
















Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.