おそらくほとんどの人が実現したいと思う、Userテーブルの情報からログインをする方法を考えてみましょう。
今回は、NazoUserBundleというサンプルバンドルを作り、そこで作業します。
chmod -R 777 app/cache app/logs php app/console generate:bundle --namespace=Nazo/UserBundle
とりあえず基本設定をします。
app/config/parameters.iniで、DBの接続設定を書きます。(省略)
DBを作成します。
php app/console doctrine:database:create
以下、「src/Nazo/UserBundle/」で作業します。
Entity/User.phpを作成します。
<?php namespace Nazo\UserBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\AdvancedUserInterface; /** * Nazo\UserBundle\Entity\User * * @ORM\Table(name="users") * @ORM\Entity */ class User implements AdvancedUserInterface { /** * @var integer $id * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var string $username * * @ORM\Column(name="username", type="string", length=255) */ private $username; /** * @var string $password * * @ORM\Column(name="password", type="string", length=255) */ private $password; /** * @var string $salt * * @ORM\Column(name="salt", type="string", length=255) */ private $salt; private $accountNonExpired = true; private $credentialsNonExpired = true; private $accountNonLocked = true; private $enabled = true; private $roles = array('ROLE_USER'); /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * {@inheritdoc} */ public function getPassword() { return $this->password; } /** * {@inheritdoc} */ public function getSalt() { return $this->salt; } /** * {@inheritdoc} */ public function getUsername() { return $this->username; } /** * Set password * * @param string $password */ public function setPassword($password) { $this->password = $password; } /** * Set salt * * @param string $salt */ public function setSalt($salt) { $this->salt = $salt; } /** * Set username * * @param string $username */ public function setUsername($username) { $this->username = $username; } /** * {@inheritdoc} */ public function getRoles() { return $this->roles; } /** * {@inheritdoc} */ public function isAccountNonExpired() { return $this->accountNonExpired; } /** * {@inheritdoc} */ public function isAccountNonLocked() { return $this->accountNonLocked; } /** * {@inheritdoc} */ public function isCredentialsNonExpired() { return $this->credentialsNonExpired; } /** * {@inheritdoc} */ public function isEnabled() { return $this->enabled; } /** * {@inheritdoc} */ public function eraseCredentials() { } /** * {@inheritDoc} */ public function equals(UserInterface $user) { if (!$user instanceof User) { return false; } if ($this->password !== $user->getPassword()) { return false; } if ($this->getSalt() !== $user->getSalt()) { return false; } if ($this->getUsername() !== $user->getUsername()) { return false; } if ($this->accountNonExpired !== $user->isAccountNonExpired()) { return false; } if ($this->accountNonLocked !== $user->isAccountNonLocked()) { return false; } if ($this->credentialsNonExpired !== $user->isCredentialsNonExpired()) { return false; } if ($this->enabled !== $user->isEnabled()) { return false; } return true; } }
Controller/DefaultController.phpを編集します。
<?php namespace Nazo\UserBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\SecurityContext; class DefaultController extends Controller { /** * @Route("/user/home") * @Template() */ public function indexAction() { return array( ); } /** * @Route("/user/login") * @Template() */ public function loginAction(Request $request) { $session = $request->getSession(); // get the login error if there is one if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) { $error = $request->attributes->get(SecurityContext::AUTHENTICATION_ERROR); } else { $error = $session->get(SecurityContext::AUTHENTICATION_ERROR); } return array( // last username entered by the user 'last_username' => $session->get(SecurityContext::LAST_USERNAME), 'error' => $error, ); } /** * @Route("/user/login_check", name="login_check") * @Template() */ public function login_checkAction() { return array(); } }
Resources/views/Default/index.html.twigを編集します。
Hello !!
Resources/views/Default/login.html.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" /> {# If you want to control the URL the user is redirected to on success (more details below) <input type="hidden" name="_target_path" value="/account" /> #} <input type="submit" name="login" /> </form>
ルートに戻って、DBにテーブルを作成します。
php app/console doctrine:schema:update --force
app/config/security.ymlを編集します。
security: encoders: Nazo\UserBundle\Entity\User: plaintext role_hierarchy: ROLE_ADMIN: ROLE_USER ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] providers: users: entity: { class: Nazo\UserBundle\Entity\User, property: username } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false login: pattern: ^/user/login$ security: false secured_area: pattern: ^/user/.* form_login: check_path: /user/login_check login_path: /user/login logout: path: /user/logout target: / #anonymous: ~ #http_basic: # realm: "Secured Demo Area" access_control: #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https } #- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
ログインは app_dev.php/user/login から試せます。 app_dev.php/user/logout にアクセスするとログアウトします。(見た目に変化はありませんが)
ログイン中かどうかは、 app_dev.php/user/home にアクセスするとわかると思います。
これでログインすることとができるようになりましたが、パスワードが平文です。よろしくないですね。
パスワードを暗号化できるように、app/config/security.ymlを編集します。
security: encoders: Nazo\UserBundle\Entity\User: algorithm: sha1 encode_as_base64: false iterations: 1 ...
しかしこれではユーザーデータを人力で入れることができません。(がんばれば入れれますが)
人力で入れるために、管理画面を作ります。
Controller/UserAdminController.php
<?php namespace Nazo\UserBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\SecurityContext; use Nazo\UserBundle\Entity\User; class UserAdminController extends Controller { /** * @Route("/admin/user/index", name="admin_user_index") * @Template() */ public function indexAction() { $em = $this->getDoctrine()->getEntityManager(); $users = $em->getRepository('NazoUserBundle:User')->findAll(); return array( 'users' => $users, ); } /** * @Route("/admin/user/create", name="admin_user_create") * @Template() */ public function createAction() { return $this->onEdit(null); } /** * @Route("/admin/user/edit", name="admin_user_edit") * @Template() */ public function editAction(Request $request) { $id = $request->get('id'); return $this->onEdit($id); } /** * protected * */ protected function onEdit($id = null) { $em = $this->getDoctrine()->getEntityManager(); $request = $this->get('request'); if ($id === null) { $user = new User(); } else { $user = $em->getRepository('NazoUserBundle:User')->find($id); } $form = $this->createFormBuilder($user) ->add('username', 'text') ->add('password', 'password') ->getForm(); if ($request->getMethod() == 'POST') { $form->bindRequest($request); if ($form->isValid()) { // encrypt password $salt = sha1(uniqid($user->getUsername(), true)); $password_raw = $user->getPassword(); $user->setSalt($salt); $ef = $this->get('security.encoder_factory'); $password = $ef->getEncoder($user)->encodePassword($password_raw, $salt); $user->setPassword($password); $em->persist($user); $em->flush(); } } return $this->render('NazoUserBundle:UserAdmin:edit.html.twig', array( 'user' => $user, 'form' => $form->createView(), )); } }
Resources/views/UserAdmin/index.html.twig
<h1>User admin</h1> <div> <a href="{{ path('admin_user_create') }}">create new user</a> </div> <table> <tr> <th>ID</th> <th>name</th> <th>action</th> </tr> {% for user in users %} <tr> <td>{{ user.id }}</td> <td>{{ user.username }}</td> <td> <a href="{{ path('admin_user_edit', {'id':user.id}) }}">edit</a> </td> </tr> {% endfor %} </table>
Resources/views/UserAdmin/edit.html.twig
<h1>Edit User</h1> <div>ID : {{ user.id }}</div> <form action="{{ path('admin_user_edit') }}" method="post" {{ form_enctype(form) }}> <input type="hidden" name="id" value="{{ user.id }}" /> {{ form_widget(form) }} <input type="submit" value="save" /> </form> <div> <a href="{{ path('admin_user_index') }}">back to list</a> </div>
これで、 app_dev.php/admin/user/index から、ユーザーを作り、そのユーザーでログインができるようになりました。