ray*_*nco 53 php authentication symfony symfony-security
我想在注册过程后立即登录用户,而不通过登录表单.
这可能吗 ?我找到了一个解决方案FOSUserBundle,但我没有在我正在进行的项目中使用它.
这是我的security.yml,我正在使用两个防火墙.纯文本编码器仅用于测试.
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
Ray\CentralBundle\Entity\Client: md5
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
in_memory:
users:
admin: { password: admin, roles: [ 'ROLE_ADMIN' ] }
entity:
entity: { class: Ray\CentralBundle\Entity\Client, property: email }
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
user_login:
pattern: ^/user/login$
anonymous: ~
admin_login:
pattern: ^/admin/login$
anonymous: ~
admin:
pattern: ^/admin
provider: in_memory
form_login:
check_path: /admin/login/process
login_path: /admin/login
default_target_path: /admin/dashboard
logout:
path: /admin/logout
target: /
site:
pattern: ^/
provider: entity
anonymous: ~
form_login:
check_path: /user/login/process
login_path: /user/login
default_target_path: /user
logout:
path: /user/logout
target: /
access_control:
- { path: ^/user/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user, roles: ROLE_USER }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Run Code Online (Sandbox Code Playgroud)
ric*_*age 98
是的,您可以通过类似于以下内容的方式执行此操作:
use Symfony\Component\EventDispatcher\EventDispatcher,
Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken,
Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
public function registerAction()
{
// ...
if ($this->get("request")->getMethod() == "POST")
{
// ... Do any password setting here etc
$em->persist($user);
$em->flush();
// Here, "public" is the name of the firewall in your security.yml
$token = new UsernamePasswordToken($user, $user->getPassword(), "public", $user->getRoles());
// For older versions of Symfony, use security.context here
$this->get("security.token_storage")->setToken($token);
// Fire the login event
// Logging the user in above the way we do it doesn't do this automatically
$event = new InteractiveLoginEvent($request, $token);
$this->get("event_dispatcher")->dispatch("security.interactive_login", $event);
// maybe redirect out here
}
}
Run Code Online (Sandbox Code Playgroud)
当您将令牌设置到上下文中时,最终触发的事件不会自动完成,而通常在使用例如登录表单或类似内容时.因此将其包含在这里的原因.您可能需要调整使用的令牌类型,具体取决于您的使用案例 - UsernamePasswordToken上面显示的是核心令牌,但如果需要,您可以使用其他令牌.
编辑:调整上述代码以解释'public'参数,并根据下面的Franco评论将用户的角色添加到令牌创建中.
如果您使用的是 symfony ^6.2,则可以使用Security::login().
对于旧版本(symfony ^5.4、^6.0、^6.1),可以执行以下操作:
public function login(User $user, Request $request, UserCheckerInterface $checker, UserAuthenticatorInterface $userAuthenticator, FormLoginAuthenticator $formLoginAuthenticator): void
{
$checker->checkPreAuth($user);
$userAuthenticator->authenticateUser($user, $formLoginAuthenticator, $request);
}
Run Code Online (Sandbox Code Playgroud)
您可以选择将此功能移至服务中,以便更轻松地进行依赖项注入:
# config/services.yaml
services:
App\Service\LoginService:
arguments:
$formLoginAuthenticator: '@security.authenticator.form_login.main'
Run Code Online (Sandbox Code Playgroud)
# src/Service/LoginService.php
namespace App\Service;
use App\Entity\User;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator;
class LoginService
{
private UserCheckerInterface $checker;
private UserAuthenticatorInterface $userAuthenticator;
private FormLoginAuthenticator $formLoginAuthenticator;
/**
* @param UserCheckerInterface $checker
* @param UserAuthenticatorInterface $userAuthenticator
* @param FormLoginAuthenticator $formLoginAuthenticator
*/
public function __construct(UserCheckerInterface $checker, UserAuthenticatorInterface $userAuthenticator, FormLoginAuthenticator $formLoginAuthenticator)
{
$this->checker = $checker;
$this->userAuthenticator = $userAuthenticator;
$this->formLoginAuthenticator = $formLoginAuthenticator;
}
public function login(User $user, Request $request): void
{
$this->checker->checkPreAuth($user);
$this->userAuthenticator->authenticateUser($user, $this->formLoginAuthenticator, $request);
}
}
Run Code Online (Sandbox Code Playgroud)
源是一个RFC,请求一种更简单的编程登录方法。这已经实现,随 symfony 6.2 一起发布。
接受的版本不适用于 symfony 3.3。用户将在下一个请求而不是当前请求中进行身份验证。原因是 ContextListener 检查先前的会话是否存在,如果不存在,它将清除安全 TokenStorage。解决这个问题的唯一方法(非常黑客)是通过在当前请求上手动初始化会话(和 cookie)来伪造先前会话的存在。
如果您找到更好的解决方案,请告诉我。
顺便说一句,我不确定这是否应该与已接受的解决方案合并。
private function logUserIn(User $user)
{
$token = new UsernamePasswordToken($user, null, "common", $user->getRoles());
$request = $this->requestStack->getMasterRequest();
if (!$request->hasPreviousSession()) {
$request->setSession($this->session);
$request->getSession()->start();
$request->cookies->set($request->getSession()->getName(), $request->getSession()->getId());
}
$this->tokenStorage->setToken($token);
$this->session->set('_security_common', serialize($token));
$event = new InteractiveLoginEvent($this->requestStack->getMasterRequest(), $token);
$this->eventDispatcher->dispatch("security.interactive_login", $event);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码假设您的防火墙名称(或共享上下文名称)是common。
| 归档时间: |
|
| 查看次数: |
28519 次 |
| 最近记录: |