duanlu1876 2019-02-21 11:37
浏览 248
已采纳

用户管理员登录,为用户提供更高的权限 - Symfony 4

Please forgive for asking, i have been working on my websites login/registration pages for some time and finally have both working seemingly flawlessly, my next task is access control so i can do some work on my forum without the need to load my SSH and make database changes.

My Composer.JSON for a list of packages i have already

"require": {
    "php": "^7.1.3",
    "ext-iconv": "*",
    "doctrine/doctrine-migrations-bundle": "^2.0",
    "knplabs/knp-markdown-bundle": "^1.7",
    "sensio/framework-extra-bundle": "^5.1",
    "symfony/asset": "^4.0",
    "symfony/console": "^4.0",
    "symfony/flex": "^1.1",
    "symfony/form": "^4.0",
    "symfony/framework-bundle": "^4.0",
    "symfony/maker-bundle": "^1.1",
    "symfony/orm-pack": "^1.0",
    "symfony/profiler-pack": "^1.0",
    "symfony/security-bundle": "^4.0",
    "symfony/translation": "^4.0",
    "symfony/twig-bundle": "^4.0",
    "symfony/validator": "^4.0",
    "symfony/yaml": "^4.0"
},
"require-dev": {
    "sensiolabs/security-checker": "^4.1",
    "symfony/dotenv": "^4.0",
    "symfony/web-server-bundle": "^4.0"

The problem i have is that my login form auto outputs 'ROLE_USER' when the database returns an empty array, however i am unclear on how i can add an object to the database JSON as i need the 'ROLE_ADMIN' string.

I understand that i could add an admin user to memory but i would like to depend solely on the database having something typed out in a doc on my root server dosent feel right to me (for some reason)

I have checked the symfony docs and looked around on here and not found anything that jumps out at me as helpful.

I would like to grant a user (me) 'ROLE_ADMIN' while all other users still get the 'ROLE_USER' that 'getRoles()' returns. my firewall already has hierarchy set up Admin inherits user so i shouldnt have trouble locking myself out of other pages.

i already have a few counts of access control implemented as shown bellow

../config/packages/security.yaml
...
access_control:
     - { path: ^/admin, roles: ROLE_ADMIN }
     - { path: ^/profile, roles: ROLE_USER }

And

../templates/forum/index.html.twig
...
{%  if is_granted('ROLE_ADMIN') %}
<li><a href="{{ path('page_admin') }}">Admin</a></li>
{% endif %}
...

Here i will drop all my controller/entity info for you guys -*all of my registration/authentication files are generated with maker-bundle

../securityController
namespace App\Controller;

use App\Form\UserType;
use App\Entity\User;
use App\Form\RegistrationFormType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;

class SecurityController extends AbstractController
{
...
Registration function
...

/**
 * @Route("/forum/login", name="app_login")
 */
public function login(AuthenticationUtils $authenticationUtils): Response
{
    // get the login error if there is one
    $error = $authenticationUtils->getLastAuthenticationError();
    // last username entered by the user
    $lastUsername = $authenticationUtils->getLastUsername();

    return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}

Entity

.../Entity/User

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * @ORM\Entity(repositoryClass="App\Repository\UserRepository")
 * @UniqueEntity(fields={"email"}, message="There is already an account with this email")
 */
class User implements UserInterface
{
/**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type="integer")
 */
private $id;

/**
 * @ORM\Column(type="string", length=180, unique=true)
 */
private $email;

/**
 * @ORM\Column(type="json")
 */
private $roles = [];

/**
 * @var string The hashed password
 * @ORM\Column(type="string")
 */
private $password;

public function getId(): ?int
{
    return $this->id;
}

public function getEmail(): ?string
{
    return $this->email;
}

public function setEmail(string $email): self
{
    $this->email = $email;

    return $this;
}

/**
 * A visual identifier that represents this user.
 *
 * @see UserInterface
 */
public function getUsername(): string
{
    return (string) $this->email;
}

/**
 * @see UserInterface
 */
public function getRoles(): array
{
    $roles = $this->roles;
    // guarantee every user at least has ROLE_USER
    $roles[] = 'ROLE_USER';

    return array_unique($roles);
}

public function setRoles(array $roles): self
{
    $this->roles = $roles;

    return $this;
}

/**
 * @see UserInterface
 */
public function getPassword(): string
{
    return (string) $this->password;
}

public function setPassword(string $password): self
{
    $this->password = $password;

    return $this;
}

/**
 * @see UserInterface
 */
public function getSalt()
{
    // not needed when using the "bcrypt" algorithm in security.yaml
}

/**
 * @see UserInterface
 */
public function eraseCredentials()
{
    // If you store any temporary, sensitive data on the user, clear it here
    // $this->plainPassword = null;
}
}

Auth

<?php

namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

class LoginAuthFormAuthenticator extends AbstractFormLoginAuthenticator
{
use TargetPathTrait;

private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;

public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
    $this->entityManager = $entityManager;
    $this->urlGenerator = $urlGenerator;
    $this->csrfTokenManager = $csrfTokenManager;
    $this->passwordEncoder = $passwordEncoder;
}

public function supports(Request $request)
{
    return 'app_login' === $request->attributes->get('_route')
        && $request->isMethod('POST');
}

public function getCredentials(Request $request)
{
    $credentials = [
        'email' => $request->request->get('email'),
        'password' => $request->request->get('password'),
        'csrf_token' => $request->request->get('_csrf_token'),
    ];
    $request->getSession()->set(
        Security::LAST_USERNAME,
        $credentials['email']
    );

    return $credentials;
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
    $token = new CsrfToken('authenticate', $credentials['csrf_token']);
    if (!$this->csrfTokenManager->isTokenValid($token)) {
        throw new InvalidCsrfTokenException();
    }

    $user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);

    if (!$user) {
        // fail authentication with a custom error
        throw new CustomUserMessageAuthenticationException('Email could not be found.');
    }

    return $user;
}

public function checkCredentials($credentials, UserInterface $user)
{
    return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
        return new RedirectResponse($targetPath);
    }

    // For example : return new RedirectResponse($this->urlGenerator->generate('some_route'));
    return new RedirectResponse($this->urlGenerator->generate('page_forum'));
}

protected function getLoginUrl()
{
    return $this->urlGenerator->generate('app_login');
}
}

Thanks in advance, any ideas are welcome

  • 写回答

1条回答 默认 最新

  • dsigg21445 2019-02-21 13:12
    关注

    To add manually role to a user in Symfony, the preferrable solution is to update straightly the database column roles for the concerned user from [] to ["ROLE_ADMIN"].

    However, if you get any troubles updating your database, you still can create a custom route like /givemeadminrole in any controller and you can use $this->getUser()->addRole("ROLE_ADMIN"); to add the ROLE_ADMIN to the connected user.

    (Of course, this works for any role.)

    Do not forget to persist your user to save changes in the database.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 c语言,请帮蒟蒻看一个题
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)