首先,不要费心去复制这段代码。这将很快在我的github上提供。 (我会更新这篇文章以防有人需要它)
您好。我正在尝试使用Steam来连接我的应用程序。所以,我试图创建自定义用户提供程序和自定义身份验证。单击“登录”按钮后,我的用户(我自己添加了一个)从数据库加载,然后重定向到我的自定义页面。在该页面中,我的调试工具栏告诉我,我已使用自定义令牌和防火墙进行了身份验证。如果我移动到另一个页面,例如“/ search”,我的调试工具栏告诉我我不再被认证了......
我做错了什么?
我正在使用Symfony 4.0.6。谢谢!
P.S。:这个脚本的灵感来自于这个:https://github.com/SirWaddles/SteamAuthBundle
P.P.S:如果我错过了任何文件,你需要它,请回复。
P.P.P.S:我认为这是void SendNotifacation()
{
var title = "Winner, Winner, Chicken Dinner";
var message = "You just won a million StackOverflow reputation points";
var intent = new Intent(BaseContext, typeof(MainActivity));
intent.SetAction("ASushiNotification");
intent.PutExtra("MessageFromSushiHangover", message);
var pending = PendingIntent.GetActivity(BaseContext, 0, intent, PendingIntentFlags.CancelCurrent);
using (var notificationManager = NotificationManager.FromContext(BaseContext))
{
Notification notification;
if (Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
{
#pragma warning disable CS0618 // Type or member is obsolete
notification = new Notification.Builder(BaseContext)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetDefaults(NotificationDefaults.All)
.SetContentIntent(pending)
.Build();
#pragma warning restore CS0618 // Type or member is obsolete
}
else
{
var myUrgentChannel = BaseContext.PackageName;
const string channelName = "Messages from SushiHangover";
NotificationChannel channel;
channel = notificationManager.GetNotificationChannel(myUrgentChannel);
if (channel == null)
{
channel = new NotificationChannel(myUrgentChannel, channelName, NotificationImportance.High);
channel.EnableVibration(true);
channel.EnableLights(true);
channel.SetSound(
RingtoneManager.GetDefaultUri(RingtoneType.Notification),
new AudioAttributes.Builder().SetUsage(AudioUsageKind.Notification).Build()
);
channel.LockscreenVisibility = NotificationVisibility.Public;
notificationManager.CreateNotificationChannel(channel);
}
channel?.Dispose();
notification = new Notification.Builder(BaseContext)
.SetChannelId(myUrgentChannel)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentIntent(pending)
.Build();
}
notificationManager.Notify(1331, notification);
notification.Dispose();
}
}
和serialize()
的问题,但我不确切知道。
Player.php
unserialize()
SteamToken.php
<?php
namespace App\Entity;
use App\Service\SteamAuth\User\SteamUserInterface;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Class Player
* @package App\Entity
*
* @ORM\Entity(repositoryClass="App\Repository\PlayerRepository")
* @ORM\Table(name="players")
*/
class Player implements UserInterface, SteamUserInterface, AdvancedUserInterface, EquatableInterface, \Serializable
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*
* @var int
*/
private $id;
/**
* @ORM\Column(type="string", length=255, )
*
* @var string
*/
private $username;
/**
* @ORM\Column(type="string", length=255)
*
* @var string
*/
private $name;
/**
* @ORM\Column(type="string", length=255)
*
* @var string
*/
private $password;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @var null|string
*/
private $avatar;
/**
* @var array
*
* @ORM\Column(type="array")
*/
private $roles;
/**
* @var \DateTime|null
*
* @ORM\Column(type="datetime", nullable=true)
*/
private $lastSync;
/**
* @var bool
*
* @ORM\Column(type="boolean")
*/
private $enabled;
/**
* @return int
*/
public function getId(): int
{
return $this->id;
}
/**
* @param int $id
*
* @return Player
*/
public function setId(int $id): Player
{
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getUsername(): string
{
return $this->username;
}
/**
* @param string $username
*
* @return Player
*/
public function setUsername(string $username): Player
{
$this->username = $username;
return $this;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*
* @return Player
*/
public function setName(string $name): Player
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* @return array
*/
public function getRoles()
{
return $this->roles;
}
/**
* @param array $roles
* @return Player
*/
public function setRoles(array $roles): Player
{
$this->roles = $roles;
return $this;
}
/**
* @return \DateTime|null
*/
public function getLastSync(): ?\DateTime
{
return $this->lastSync;
}
/**
* @param \DateTime|null $lastSync
* @return Player
*/
public function setLastSync(?\DateTime $lastSync): Player
{
$this->lastSync = $lastSync;
return $this;
}
/**
* @return null|string
*/
public function getSalt()
{
return null;
}
/**
* @param string $password
* @return Player
*/
public function setPassword(string $password): Player
{
$this->password = $password;
return $this;
}
/**
* @return null|string
*/
public function getAvatar(): ?string
{
return $this->avatar;
}
/**
* @param null|string $avatar
*
* @return Player
*/
public function setAvatar(?string $avatar): Player
{
$this->avatar = $avatar;
return $this;
}
/**
* {@inheritdoc}
*/
public function eraseCredentials()
{
}
/**
* {@inheritdoc}
*/
public function isAccountNonExpired()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isAccountNonLocked()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isCredentialsNonExpired()
{
return true;
}
/**
* {@inheritdoc}
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* @param bool|null $enabled
* @return Player
*/
public function setEnabled(?bool $enabled): Player
{
$this->enabled = $enabled;
return $this;
}
/**
* {@inheritdoc}
*/
public function isEqualTo(UserInterface $user)
{
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize([
$this->id,
$this->username,
$this->name,
$this->avatar,
$this->password,
$this->enabled
]);
}
/**
* {@inheritdoc}
*/
public function unserialize($data)
{
list($this->id, $this->username, $this->name, $this->avatar, $this->password, $this->enabled) = unserialize($data);
}
/**
* @return string
*/
public function __toString()
{
return $this->getUsername() ?? '-';
}
}
SteamListener.php
<?php
namespace App\Service\SteamAuth\Token;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
/**
* Class SteamToken
* @package App\Service\SteamAuth\Token
*/
class SteamToken extends AbstractToken
{
/**
* {@inheritdoc}
*/
public function __construct(array $roles = [])
{
parent::__construct($roles);
$this->setAuthenticated(count($roles) > 0);
}
/**
* {@inheritdoc}
*/
public function setAttributes(array $attributes)
{
foreach ($attributes as $key => $attribute) {
$key = str_replace("openid_", "openid.", $key);
$this->setAttribute($key, $attribute);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getCredentials()
{
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize([
$this->getUser(),
$this->isAuthenticated(),
$this->getAttributes()
]);
}
/**
* {@inheritdoc}
*/
public function unserialize($data)
{
$data = unserialize($data);
$this->setUser($data[0]);
$this->setAuthenticated($data[1]);
$this->setAttributes($data[2]);
}
}
SteamProvider.php
<?php
namespace App\Service\SteamAuth\Firewall;
use App\Service\SteamAuth\Token\SteamToken;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
/**
* Class SteamListener
* @package App\Service\SteamAuth
*/
class SteamListener implements ListenerInterface
{
/**
* @var TokenStorageInterface
*/
private $tokenStorage;
/**
* @var AuthenticationManagerInterface
*/
private $authentication;
/**
* SteamListener constructor.
*
* @param TokenStorageInterface $tokenStorage
* @param AuthenticationManagerInterface $authentication
*/
public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authentication)
{
$this->tokenStorage = $tokenStorage;
$this->authentication = $authentication;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
if($request->get('_route') === 'login_check') {
$token = new SteamToken();
$token->setUser(str_replace("http://steamcommunity.com/openid/id/", "", $request->query->get('openid_claimed_id')));
$token->setAttributes($request->query->all());
try {
$authToken = $this->authentication->authenticate($token);
$this->tokenStorage->setToken($authToken);
return;
} catch (AuthenticationException $exception) {
}
}
$response = new Response();
$response->setStatusCode(Response::HTTP_FORBIDDEN);
$event->setResponse($response);
return;
}
}
SteamUserProvider.php
<?php
namespace App\Service\SteamAuth\Authentication;
use App\Service\SteamAuth\Token\SteamToken;
use GuzzleHttp\Client;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Class SteamProvider
* @package App\Service\SteamAuth\Provider
*/
class SteamProvider implements AuthenticationProviderInterface
{
/**
* @var UserProviderInterface
*/
private $userProvider;
/**
* @var Client
*/
private $client;
/**
* SteamProvider constructor.
*
* @param UserProviderInterface $userProvider
* @param Client $client
*/
public function __construct(UserProviderInterface $userProvider, Client $client)
{
$this->userProvider = $userProvider;
$this->client = $client;
}
/**
* {@inheritdoc}
*/
public function authenticate(TokenInterface $token)
{
if ($token->getAttribute('openid.ns') !== "http://specs.openid.net/auth/2.0") {
throw new AuthenticationException("Invalid token !");
}
$checkAuth = $token->getAttributes();
$checkAuth['openid.mode'] = 'check_authentication';
$response = $this->client->request('GET', 'login', ['query' => $checkAuth]);
if ((string)$response->getBody() === "ns:http://specs.openid.net/auth/2.0\nis_valid:true\n") {
$user = $this->userProvider->loadUserByUsername($token->getUsername());
$authToken = new SteamToken($user->getRoles());
$authToken->setUser($user);
return $authToken;
}
throw new AuthenticationException("Invalid token !");
}
/**
* {@inheritdoc}
*/
public function supports(TokenInterface $token)
{
return $token instanceof SteamToken;
}
}
services.yaml
<?php
namespace App\Service\SteamAuth\User;
use App\Entity\Player;
use App\Service\SteamAuth\SteamUserService;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Class SteamUserProvider
* @package App\Service\SteamAuth\User
*/
class SteamUserProvider implements UserProviderInterface
{
/**
* @var EntityManager
*/
private $entityManager;
/**
* @var string
*/
private $userClass;
/**
* @var SteamUserService
*/
private $userService;
/**
* SteamUserProvider constructor.
*
* @param EntityManager $entityManager
* @param SteamUserService $userService
* @param string $userClass
*/
public function __construct(EntityManager $entityManager, SteamUserService $userService, string $userClass)
{
$this->entityManager = $entityManager;
$this->userService = $userService;
$this->userClass = $userClass;
}
/**
* {@inheritdoc}
*/
public function loadUserByUsername($username)
{
$repository = $this->entityManager->getRepository($this->userClass);
$player = $repository->findOneBy(['username' => $username]);
if (!$player) {
/**
* @var $player Player
*/
$player = new $this->userClass();
$player->setUsername($username);
$player->setPassword(md5(random_bytes(15)));
$player->setRoles(['ROLE_USER']);
$player->setEnabled(1);
$player = $this->userService->updateUserEntry($player);
$this->entityManager->persist($player);
$this->entityManager->flush($player);
}
/// if last update....
return $player;
}
/**
* {@inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof SteamUserInterface) {
throw new UnsupportedUserException("User not supported!");
}
return $this->loadUserByUsername($user->getUsername());
}
/**
* {@inheritdoc}
*/
public function supportsClass($class)
{
return $class === $this->userClass;
}
}
security.yaml
services:
...
# Aliases
GuzzleHttp\Client: '@eight_points_guzzle.client.login'
# Log In System
app.steam_user.service:
class: App\Service\SteamAuth\SteamUserService
arguments: ['@eight_points_guzzle.client.steam', '%steam_api_key%']
app.steam_user.provider:
class: App\Service\SteamAuth\User\SteamUserProvider
arguments:
$entityManager: '@doctrine.orm.default_entity_manager'
$userService: '@app.steam_user.service'
$userClass: '%steam_user_class%'
app.steam.provider:
class: App\Service\SteamAuth\Authentication\SteamProvider
arguments:
$userProvider: '@app.steam_user.provider'
$client: '@eight_points_guzzle.client.login'
app.steam.listener:
class: App\Service\SteamAuth\Firewall\SteamListener
编辑:如果我security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
steamauth:
id: app.steam_user.provider
firewalls:
steam_auth:
pattern: ^/login_check
stateless: true
steam: ~
form_login:
csrf_token_generator: security.csrf.token_manager
remember_me:
secret: '%kernel.secret%'
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
和刷新前的那个页面,我会得到:dump($this->get('session')->all())
答案 0 :(得分:0)
我遇到了类似的问题。
我的序列化过程中缺少一个属性:isActive 我从来不明白为什么,但是当这个属性是我的序列化/反序列化过程时,它工作正常,如果没有,它根本不起作用。
这是我的来源:https://github.com/matthieuleorat/documentManager/blob/master/src/Entity/User.php#L253
文档:http://symfony.com/doc/current/security/entity_provider.html#security-serialize-equatable
希望有所帮助。
答案 1 :(得分:0)
您是否启用了module_suhosin7?
我们在启用了suhosin7的会话中遇到了问题。 事实上,它增加了一些关于会话和cookie管理的规则。
如果启用,请尝试禁用它并检查它是否有效。
有一个关于使用suhosin7进行会话加密的已知问题: https://github.com/sektioneins/suhosin7/issues/21
答案 2 :(得分:0)
SteamListener.php中的这一行阻止任何其他路由起作用。
$request = $event->getRequest();
if($request->get('_route') === 'login_check') {
[...]
}
$response = new Response();
$response->setStatusCode(Response::HTTP_FORBIDDEN);
$event->setResponse($response);
每次导航到页面时都会调用防火墙handle()函数,因此如果将其他页面状态设置为禁止,则无法在登录以外的其他页面上导航。
这应该通过删除它。如果问题解决了,请告诉我
答案 3 :(得分:0)
经过大量的工作,我决定再次研究一个Steam身份验证包,我找到了一个Symfony 4,我确认它有效。