文章目录
2016-01-12
by:xiaoxia
一、访问控制【access_control】
1.1、机制
主要根据url分层控制,你用匹配,指定某一类url只能特定角色的用户使用。
1.2、配置例子
在默认配置基础上添加如下域:
security: access_control: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/, role:[ROLE_STUDENT,ROLE_TEACHER,ROLE_ADMIN] }
1.3、效果
1.4、注意
1、有些页面必须是所有用户都能访问的,如:login、login_check;
2、用户指定时可以指定用户的数组;
二、关于密码源【provider】
上面提出来路径控制,但是用户和密码哪儿来的呢,在symfony中,是通过provider来提供的。也可以有不同的数据源指定。
2.1、security硬密码
2.1.1、机制
直接将密码写到security文件中。一般不会这么用,不做详细介绍。
2.1.2、配置实例
security: providers: in_memory: memory: users: xia: password: xia roles: 'ROLE_USER' admin: password: xiaoxia roles: 'ROLE_ADMIN' encoders: Symfony\Component\Security\Core\User\User: plaintext firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: pattern: ^/ http_basic: ~ provider: in_memory
2.1.3、效果
2.2、数据库动态密码-Entity
2.2.1、数据库
1、设计设计
'id', 'int(11)', 'NO', 'PRI', NULL, 'auto_increment' 'username', 'varchar(45)', 'NO', 'UNI', NULL, '' 'password', 'varchar(256)', 'NO', '', NULL, '' 'role', 'varchar(45)', 'YES', '', BULL, '' 'rid', 'varchar(45)', 'YES', '', NULL, '' 'nickname', 'varchar(45)', 'YES', '', NULL, '' 'currentIp', 'varchar(45)', 'YES', '', NULL, ''
2、生成Entity,根据实际情况而定
app/console doctrine:mapping:import --force CellcomDBBundle yml app/console doctrine:generate:entities CellcomDBBundle --no-backup
2.2.2、机制
如果使用了doctrine作为数据持久层(ORM),这可以可以直接讲数据表的User的Entity作为数据源。不过需要做一些修改:
1、让User的Entity类实现UserInterface接口;
2、接口有:getRoles()、getPassword()、getSalt()、getUsername()、eraseCredentials();
3、必要时也可以实现Serializable接口,serialize()、unserialize()。
2.2.3、实例
1、修改User的Entity类,只列出来修改部分:
<?php namespace Cellcom\DBBundle\Entity; use Symfony\Component\Security\Core\User\UserInterface; use Doctrine\ORM\Mapping as ORM; class User implements UserInterface, \Serializable { /** Fonctions UserInterface*/ public function eraseCredentials( { } public function getRoles() { return (Array)$this->role; } public function equals(UserInterface $user) { return $user->getUsername() === $this->username; } //public function getUsername() 已经自动生成 //public function getPassword() 已经自动生成 public function isEnabled() { return true; } public function getSalt() { return ''; } /** @see \Serializable::serialize() */ public function serialize() { return serialize(array( $this->id, $this->username, $this->password, // see section on salt below // $this->salt, )); } /** @see \Serializable::unserialize() */ public function unserialize($serialized) { list ( $this->id, $this->username, $this->password, // see section on salt below // $this->salt ) = unserialize($serialized); }
2、security配置:
security: providers: cellcom_db_provider: entity: class: CellcomDBBundle:User property: username encoders: Cellcom\DBBundle\Entity\User: algorithm: bcrypt firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: pattern: ^/ http_basic: ~ provider: cellcom_db_provider anonymous: ~ access_control: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/login_check,roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/, role:[ROLE_STUDENT,ROLE_TEACHER,ROLE_ADMIN] }
2.2.4、效果
2.2.5、注意
数据库User表可以灵活设计,字段名没有要求,UserInterface中的接口实现的可以做相应的调整。但是如果数据表中设计成:username、password、roles等时,上面接口的实现可以通过doctrine命令自动生成相应的代码,减少工作量,但会牺牲灵活性。
2.3、数据库动态密码-UserProvider
上面介绍的2.2其实是框架自动做了很多事情,但是是封闭的,不便于扩展。比如记录当前登陆用户记录到数据库中。为此我们可以自定义UserProvider来实现。
2.3.1、数据库
同2.2.1
2.3.2、机制
这种情况下需要实现两个接口:UserInterface和UserProviderInterface。
UserInterface可以使用2.2中的Entity,也可以自定义一个类,只需要实现相应的接口就可以,接口在2.1.1中已经介绍了。这样在系统架构时就不一定需要ORM层了。
UserProviderInterface主要是为登陆提供相应的数据,需要实现的接口是:loadUserByUsername()、refreshUser()、supportsClass()。
2.3.3、实例
1、UserInterface的User的Entity类
同2.2.3
2、UserProviderInterface的UserProvider类
<?php namespace Cellcom\Service\User; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Exception\LockedException; use Cellcom\Service\Common\ServiceKernel; use Cellcom\Service\Common\BaseService; use Cellcom\DBBundle\Entity\User; class UserProvider extends BaseService implements UserProviderInterface { public function __construct ($container) { $this->container = $container; } public function loadUserByUsername ($username) { $user = $this->getService('cellcom.user')->getUserByLoginField($username); if (empty($user)) { throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username)); } $user->setCurrentip($this->container->get('request')->getClientIp()); ServiceKernel::instance()->setCurrentUser($user); $this->getService('cellcom.user')->updateUser($user); return $user; } public function refreshUser (UserInterface $user) { if (! $user instanceof User) { throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); } return $this->loadUserByUsername($user->getUsername()); } public function supportsClass ($class) { return $class === 'Cellcom\DBBundle\Entity\User'; } }
3、UserService服务
<?php namespace Cellcom\Service\User; use Cellcom\Service\Common\BaseService; class UserService extends BaseService { public function getUserByLoginField($username) { if(!isset($username)) return null; $user = $this->getDBRepository('CellcomDBBundle:User')->findOneByUsername($username); return !isset($user) ? null : $user; } public function updateUser($user) { if (!$user) { return false; } $this->getEM()->persist($user); $this->getEM()->flush(); } }
4、services服务配置
services: cellcom.user: class: Cellcom\Service\User\UserService arguments: [] cellcom.user_provider: class: Cellcom\Service\User\UserProvider arguments: [@service_container]
5、security配置
security: providers: cellcom_db_provider: id: cellcom.user_provider encoders: Cellcom\DBBundle\Entity\User: algorithm: bcrypt firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: pattern: ^/ http_basic: ~ provider: cellcom_db_provider anonymous: ~ access_control: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/, role:[ROLE_STUDENT,ROLE_TEACHER,ROLE_ADMIN] }
2.3.4、效果
2.3.5、注意
这种方法比较灵活,注意UserInterface中提供的get属性可以在twig中{{ app.user.nickname }}来直接调用。
三、关于认证【待补充】
3.1、
四、登陆页面
4.1、机制
实现login路由的接口即可,比较简单。
4.2、实例
1、security配置:
security: providers: cellcom_db_provider: id: cellcom.user_provider encoders: Cellcom\DBBundle\Entity\User: algorithm: bcrypt firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false main: pattern: ^/ http_basic: ~ provider: cellcom_db_provider anonymous: ~ form_login: login_path: login check_path: login_check access_control: - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/, role:[ROLE_STUDENT,ROLE_TEACHER,ROLE_ADMIN] }
2、Controller
<?php namespace Cellcom\WebBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Security; class SecurityController extends Controller { public function loginAction(Request $request) { $session = $request->getSession(); // get the login error if there is one if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { $error = $request->attributes->get(Security::AUTHENTICATION_ERROR); } elseif (null !== $session && $session->has(Security::AUTHENTICATION_ERROR)) { $error = $session->get(Security::AUTHENTICATION_ERROR); $session->remove(Security::AUTHENTICATION_ERROR); } else { $error = ''; } // last username entered by the user $lastUsername = (null === $session) ? '' : $session->get(Security::LAST_USERNAME); return $this->render( 'CellcomWebBundle:Security:login.html.twig', array( 'last_username' => $lastUsername, 'error' => $error, )); } }
3、twig页面
{% if error %} <div>{{ error.message }}</div> {% endif %} <form action="{{ path('login_check') }}" method="post"> <label for="username">Username:</label> <input type="text" id="username" name="_username" value="{{ last_username }}" /> <label for="password">Password:</label> <input type="password" id="password" name="_password" /> <button type="submit">login</button> </form>
4.3、效果
4.4、注意
表单中的name="_username"和name="_password",不过也可以自己配置,不做多介绍。
五、参考:
1、security中文介绍:http://www.newlifeclan.com/symfony/archives/242
2、DB作为数据源:http://symfony.com/doc/2.7/cookbook/security/entity_provider.html
3、登陆表单:http://symfony.com/doc/current/cookbook/security/form_login_setup.html
4、认证:http://symfony.com/doc/2.7/cookbook/security/custom_authentication_provider.html
转载标明出处:https://blog.evanxia.com/2016/02/77