gpt4 book ai didi

symfony - 使用外部 REST API 在 Symfony 3 中自定义身份验证

转载 作者:行者123 更新时间:2023-12-02 14:06:05 31 4
gpt4 key购买 nike

我想编写一个基本的登录表单,它通过向外部 REST API 发送请求来对用户进行身份验证。外部 API 接收登录名/密码,如果凭据正确,则返回 200(确定)。但是,我无法通过 UserProviderInterface 实现它,因为外部 REST API 在回复中给了我密码。 (我无法在loadUserByUsername方法中填写用户密码)。

我在这里找到了一个有效的解决方案,但它使用了 Symfony 3 中已删除的类:Symfony2 custom connection by web service

我使用自定义身份验证器进行了测试,该验证器仅检查密码是否为“toto”,但我遇到了重定向循环,并且我的虚拟 UserProvider 仍被调用:

<?php
namespace AppBundle\Security\User;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface;

class WebserviceAuthenticator implements SimpleFormAuthenticatorInterface
{
private $encoder;

public function __construct(UserPasswordEncoderInterface $encoder)
{
$this->encoder = $encoder;
}

public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
{
$user = new WebserviceUser($token->getUsername(), $token->getCredentials(), null, ['ROLE_ADMIN']);

// HERE : call the external REST API
if ($token->getCredentials() === 'toto') {
$token = new UsernamePasswordToken(
$user,
$user->getPassword(),
'main',
$user->getRoles()
);
return $token;
}
throw new CustomUserMessageAuthenticationException('Invalid username or password');
}

public function supportsToken(TokenInterface $token, $providerKey)
{
return $token instanceof UsernamePasswordToken
&& $token->getProviderKey() === $providerKey;
}

public function createToken(Request $request, $username, $password, $providerKey)
{
return new UsernamePasswordToken($username, $password, $providerKey);
}
}

最佳答案

我让它与该实现一起工作:

安全.yml

providers:
webservice:
id: AppBundle\Security\User\WebserviceUserProvider

encoders:
AppBundle\Entity\WebserviceUser: plaintext

firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false

main:
anonymous: ~
provider: webservice
pattern: ^/
form_login:
check_path: login
login_path: login
use_forward: true
logout: ~
guard:
authenticators:
- app.webservice_authenticator

login:
pattern: ^/login$
anonymous: ~

access_control:
- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/cache, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_USER }

role_hierarchy:
ROLE_ADMIN: ROLE_USER

服务.yml

services:
app.webservice_authenticator:
class: AppBundle\Security\User\WebserviceAuthenticator

用户提供者

namespace AppBundle\Security\User;

use AppBundle\Entity\WebserviceUser;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;

class WebserviceUserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
return new WebserviceUser($username, null, null, ['ROLE_USER']);
}

public function refreshUser(UserInterface $user)
{
if (!$user instanceof WebserviceUser) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $user;
}

public function supportsClass($class)
{
return WebserviceUser::class === $class;
}
}

验证器

<?php

namespace AppBundle\Security\User;

use AppBundle\Service\RestClient;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;


class WebserviceAuthenticator extends AbstractFormLoginAuthenticator
{
private $container;
private $restClient;

public function __construct(ContainerInterface $container, RestClient $restClient)
{
$this->container = $container;
$this->restClient = $restClient;
}

public function getCredentials(Request $request)
{
if ($request->getPathInfo() != '/login' || $request->getMethod() != 'POST') {
return;
}

$username = $request->request->get('_username');
$request->getSession()->set(Security::LAST_USERNAME, $username);
$password = $request->request->get('_password');

return array(
'username' => $username,
'password' => $password
);
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
//dump($credentials); die();
if (array_key_exists('username', $credentials) == false) {
return null;
}
$username = $credentials['username'];
$password = strtoupper($credentials['password']);
if ($username == '') {
return null;
}

// Here the business code, provide your own implementtion
if ($this->restClient->IsValidLogin($username, $password)) {
return new WebserviceUser($username, $password, null, ['ROLE_USER']);
} else {
throw new CustomUserMessageAuthenticationException('Invalid credentials');
}
}

public function checkCredentials($credentials, UserInterface $user)
{
return true;
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
// AJAX! Return some JSON
if ($request->isXmlHttpRequest()) {
return new JsonResponse(array('message' => $exception->getMessageKey()), 403);
}

// for non-AJAX requests, return the normal redirect
return parent::onAuthenticationFailure($request, $exception);
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// AJAX! Return some JSON
if ($request->isXmlHttpRequest()) {
return new JsonResponse(array('userId' => $token->getUser()->getId()));
}

// for non-AJAX requests, return the normal redirect
return parent::onAuthenticationSuccess($request, $token, $providerKey);
}

protected function getLoginUrl()
{
return $this->container->get('router')
->generate('login');
}

protected function getDefaultSuccessRedirectUrl()
{
return $this->container->get('router')
->generate('homepage');
}
}

诀窍似乎是:

  1. 在身份验证器的 getUser 方法中实现密码验证,并让 checkCredentials 方法始终返回 true。
  2. 禁用UserProvider的refreshUser方法

关于symfony - 使用外部 REST API 在 Symfony 3 中自定义身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46362122/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com