Added Google auth.

This commit is contained in:
2020-01-11 18:55:08 +03:00
parent 383425d7de
commit 06f20d2a4f
16 changed files with 1074 additions and 16 deletions
+2 -1
View File
@@ -29,5 +29,6 @@ APP_SECRET=2a37fd338bcb9eeec4645dd50db620e0
# For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db" # For an SQLite database, use: "sqlite:///%kernel.project_dir%/var/data.db"
# For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8" # For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8"
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7 #DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7
###< doctrine/doctrine-bundle ### ###< doctrine/doctrine-bundle ###
+2
View File
@@ -5,6 +5,8 @@
"php": "^7.1.3", "php": "^7.1.3",
"ext-ctype": "*", "ext-ctype": "*",
"ext-iconv": "*", "ext-iconv": "*",
"knpuniversity/oauth2-client-bundle": "^1.32",
"league/oauth2-google": "^3.0",
"sensio/framework-extra-bundle": "^5.5", "sensio/framework-extra-bundle": "^5.5",
"symfony/apache-pack": "^1.0", "symfony/apache-pack": "^1.0",
"symfony/asset": "4.4.*", "symfony/asset": "4.4.*",
Generated
+455 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "d6e8bc8b46d0e946a35999599cf79156", "content-hash": "067b0e9ecd420b1b48945900bf4c8987",
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
@@ -1204,6 +1204,195 @@
], ],
"time": "2020-01-05T14:11:20+00:00" "time": "2020-01-05T14:11:20+00:00"
}, },
{
"name": "guzzlehttp/guzzle",
"version": "6.5.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "43ece0e75098b7ecd8d13918293029e555a50f82"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/43ece0e75098b7ecd8d13918293029e555a50f82",
"reference": "43ece0e75098b7ecd8d13918293029e555a50f82",
"shasum": ""
},
"require": {
"ext-json": "*",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.6.1",
"php": ">=5.5"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.1"
},
"suggest": {
"ext-intl": "Required for Internationalized Domain Name (IDN) support",
"psr/log": "Required for using the Log middleware"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "6.5-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle is a PHP HTTP client library",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"time": "2019-12-23T11:57:10+00:00"
},
{
"name": "guzzlehttp/promises",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "Guzzle promises library",
"keywords": [
"promise"
],
"time": "2016-12-20T10:07:11+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "1.6.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "239400de7a173fe9901b9ac7c06497751f00727a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/239400de7a173fe9901b9ac7c06497751f00727a",
"reference": "239400de7a173fe9901b9ac7c06497751f00727a",
"shasum": ""
},
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0",
"ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"ext-zlib": "*",
"phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
},
"suggest": {
"zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6-dev"
}
},
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Tobias Schultze",
"homepage": "https://github.com/Tobion"
}
],
"description": "PSR-7 message implementation that also provides common utility methods",
"keywords": [
"http",
"message",
"psr-7",
"request",
"response",
"stream",
"uri",
"url"
],
"time": "2019-07-01T23:21:34+00:00"
},
{ {
"name": "jdorn/sql-formatter", "name": "jdorn/sql-formatter",
"version": "v1.2.17", "version": "v1.2.17",
@@ -1254,6 +1443,181 @@
], ],
"time": "2014-01-12T16:20:24+00:00" "time": "2014-01-12T16:20:24+00:00"
}, },
{
"name": "knpuniversity/oauth2-client-bundle",
"version": "v1.32.0",
"source": {
"type": "git",
"url": "https://github.com/knpuniversity/oauth2-client-bundle.git",
"reference": "825b0c4512e51615318c8fbd4a57c7e65a57216d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/knpuniversity/oauth2-client-bundle/zipball/825b0c4512e51615318c8fbd4a57c7e65a57216d",
"reference": "825b0c4512e51615318c8fbd4a57c7e65a57216d",
"shasum": ""
},
"require": {
"league/oauth2-client": "^1.0|^2.0",
"php": "^7.1.3",
"symfony/dependency-injection": "^3.4|^4.0|^5.0",
"symfony/framework-bundle": "^3.4|^4.0|^5.0",
"symfony/http-foundation": "^3.4|^4.0|^5.0",
"symfony/routing": "^3.4|^4.0|^5.0"
},
"require-dev": {
"league/oauth2-facebook": "^1.1|^2.0",
"phpspec/prophecy": "^1.8",
"phpstan/phpstan": "^0.11.16",
"symfony/phpunit-bridge": "^4.3|^5.0",
"symfony/security-guard": "^3.4|^4.0|^5.0",
"symfony/yaml": "^3.4|^4.0|^5.0"
},
"suggest": {
"symfony/security-guard": "For integration with Symfony's Guard Security layer"
},
"type": "symfony-bundle",
"autoload": {
"psr-4": {
"KnpU\\OAuth2ClientBundle\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ryan Weaver",
"email": "ryan@knpuniversity.com"
}
],
"description": "Integration with league/oauth2-client to provide services",
"homepage": "http://knpuniversity.com",
"keywords": [
"oauth",
"oauth2"
],
"time": "2020-01-10T15:50:30+00:00"
},
{
"name": "league/oauth2-client",
"version": "2.4.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-client.git",
"reference": "cc114abc622a53af969e8664722e84ca36257530"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/cc114abc622a53af969e8664722e84ca36257530",
"reference": "cc114abc622a53af969e8664722e84ca36257530",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^6.0",
"paragonie/random_compat": "^1|^2|^9.99",
"php": "^5.6|^7.0"
},
"require-dev": {
"eloquent/liberator": "^2.0",
"eloquent/phony-phpunit": "^1.0|^3.0",
"jakub-onderka/php-parallel-lint": "^0.9.2",
"phpunit/phpunit": "^5.7|^6.0",
"squizlabs/php_codesniffer": "^2.3|^3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-2.x": "2.0.x-dev"
}
},
"autoload": {
"psr-4": {
"League\\OAuth2\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alex Bilbie",
"email": "hello@alexbilbie.com",
"homepage": "http://www.alexbilbie.com",
"role": "Developer"
},
{
"name": "Woody Gilk",
"homepage": "https://github.com/shadowhand",
"role": "Contributor"
}
],
"description": "OAuth 2.0 Client Library",
"keywords": [
"Authentication",
"SSO",
"authorization",
"identity",
"idp",
"oauth",
"oauth2",
"single sign on"
],
"time": "2018-11-22T18:33:57+00:00"
},
{
"name": "league/oauth2-google",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/oauth2-google.git",
"reference": "cfe9b0ae69eb5dbac64a282f04410b731f6b9c04"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/oauth2-google/zipball/cfe9b0ae69eb5dbac64a282f04410b731f6b9c04",
"reference": "cfe9b0ae69eb5dbac64a282f04410b731f6b9c04",
"shasum": ""
},
"require": {
"league/oauth2-client": "^2.0"
},
"require-dev": {
"eloquent/phony-phpunit": "^2.0",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^6.0",
"squizlabs/php_codesniffer": "^2.0"
},
"type": "library",
"autoload": {
"psr-4": {
"League\\OAuth2\\Client\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Woody Gilk",
"email": "woody.gilk@gmail.com",
"homepage": "http://shadowhand.me"
}
],
"description": "Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client",
"keywords": [
"Authentication",
"authorization",
"client",
"google",
"oauth",
"oauth2"
],
"time": "2019-11-16T14:11:06+00:00"
},
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
"version": "1.25.3", "version": "1.25.3",
@@ -1698,6 +2062,56 @@
], ],
"time": "2017-02-14T16:28:37+00:00" "time": "2017-02-14T16:28:37+00:00"
}, },
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2016-08-06T14:39:51+00:00"
},
{ {
"name": "psr/link", "name": "psr/link",
"version": "1.0.0", "version": "1.0.0",
@@ -1794,6 +2208,46 @@
], ],
"time": "2019-11-01T11:05:21+00:00" "time": "2019-11-01T11:05:21+00:00"
}, },
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
"reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
"reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
"php": ">=5.6"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^5 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Ralph Khattar",
"email": "ralph.khattar@gmail.com"
}
],
"description": "A polyfill for getallheaders.",
"time": "2019-03-08T08:55:37+00:00"
},
{ {
"name": "sensio/framework-extra-bundle", "name": "sensio/framework-extra-bundle",
"version": "v5.5.3", "version": "v5.5.3",
+1
View File
@@ -12,4 +12,5 @@ return [
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
]; ];
+13
View File
@@ -0,0 +1,13 @@
knpu_oauth2_client:
clients:
# configure your clients as described here: https://github.com/knpuniversity/oauth2-client-bundle#configuration
# the key "google" can be anything, it
# will create a service: "knpu.oauth2.client.google"
google:
type: google
client_id: '%env(OAUTH_GOOGLE_ID)%'
client_secret: '%env(OAUTH_GOOGLE_SECRET)%'
# the route that you're redirected to after
redirect_route: connect_google_check
redirect_params: {}
+14 -13
View File
@@ -1,22 +1,23 @@
security: security:
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
# https://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers: providers:
in_memory: { memory: null } my_provider:
entity: { class: App:User, property: username }
firewalls: firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev: dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/ pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false security: false
main: main:
anonymous: lazy anonymous: ~
logout:
path: /logout
target: /
logout_on_user_change: true
# activate different ways to authenticate guard:
# https://symfony.com/doc/current/security.html#firewalls-authentication authenticators:
- App\Security\GoogleAuthenticator
# https://symfony.com/doc/current/security/impersonating_user.html
# switch_user: true
# 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: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
+4
View File
@@ -1,3 +1,7 @@
#index: #index:
# path: / # path: /
# controller: App\Controller\DefaultController::index # controller: App\Controller\DefaultController::index
app_logout:
path: /logout
methods: GET
+40
View File
@@ -0,0 +1,40 @@
<?php
namespace App\Controller;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class GoogleController extends AbstractController
{
/**
* Link to this controller to start the "connect" process
*
* @Route("/connect/google", name="connect_google")
* @param ClientRegistry $clientRegistry
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function connectAction(ClientRegistry $clientRegistry)
{
return $clientRegistry->getClient('google')->redirect();
}
/**
* Facebook redirects to back here afterwards
*
* @Route("/connect/google/check", name="connect_google_check")
* @param Request $request
* @return JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function connectCheckAction(Request $request)
{
if (!$this->getUser()) {
return new JsonResponse(['status' => false, 'message' => 'User not found!']);
}
return $this->redirectToRoute('app_main_index');
}
}
+176
View File
@@ -0,0 +1,176 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User implements UserInterface
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $email;
/**
* @ORM\Column(type="string", length=20)
*/
private $name;
/**
* @ORM\Column(type="datetime")
*/
private $created_at;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $avatar;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $guid;
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;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getAvatar(): ?string
{
return $this->avatar;
}
public function setAvatar(?string $avatar): self
{
$this->avatar = $avatar;
return $this;
}
public function getGuid(): ?string
{
return $this->guid;
}
public function setGuid(?string $guid): self
{
$this->guid = $guid;
return $this;
}
/**
* Returns the roles granted to the user.
*
* <code>
* public function getRoles()
* {
* return array('ROLE_USER');
* }
* </code>
*
* Alternatively, the roles might be stored on a ``roles`` property,
* and populated in any number of different ways when the user object
* is created.
*
* @return (Role|string)[] The user roles
*/
public function getRoles()
{
return ['ROLE_USER'];
}
/**
* Returns the password used to authenticate the user.
*
* This should be the encoded password. On authentication, a plain-text
* password will be salted, encoded, and then compared to this value.
*
* @return string The password
*/
public function getPassword()
{
return null;
}
/**
* Returns the salt that was originally used to encode the password.
*
* This can return null if the password was not encoded using a salt.
*
* @return string|null The salt
*/
public function getSalt()
{
return null;
}
/**
* Returns the username used to authenticate the user.
*
* @return string The username
*/
public function getUsername()
{
return $this->email;
}
/**
* Removes sensitive data from the user.
*
* This is important if, at any given point, sensitive information like
* the plain-text password is stored on this object.
*/
public function eraseCredentials()
{
return null;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20200111120854 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('CREATE TABLE user (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(255) NOT NULL, name VARCHAR(20) NOT NULL, created_at DATETIME NOT NULL, avatar VARCHAR(255) DEFAULT NULL, guid VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'mysql', 'Migration can only be executed safely on \'mysql\'.');
$this->addSql('DROP TABLE user');
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
/**
* @method User|null find($id, $lockMode = null, $lockVersion = null)
* @method User|null findOneBy(array $criteria, array $orderBy = null)
* @method User[] findAll()
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
// /**
// * @return User[] Returns an array of User objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->orderBy('u.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?User
{
return $this->createQueryBuilder('u')
->andWhere('u.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
+129
View File
@@ -0,0 +1,129 @@
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator;
use League\OAuth2\Client\Provider\GoogleUser;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class GoogleAuthenticator extends SocialAuthenticator
{
private $clientRegistry;
private $em;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $em)
{
$this->clientRegistry = $clientRegistry;
$this->em = $em;
}
public function supports(Request $request)
{
return $request->getPathInfo() === '/connect/google/check' && $request->isMethod('GET');
}
public function getCredentials(Request $request)
{
return $this->fetchAccessToken($this->getGoogleClient());
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
/** @var GoogleUser $googleUser */
$googleUser = $this->getGoogleClient()->fetchUserFromToken($credentials);
$email = $googleUser->getEmail();
$user = $this->em->getRepository('App:User')->findOneBy(['email' => $email]);
if (!$user) {
$user = new User();
$user->setEmail($googleUser->getEmail());
$user->setName($googleUser->getName());
$user->setAvatar($googleUser->getAvatar());
$user->setGuid($googleUser->getId());
$user->setCreatedAt(new \DateTime(date('Y-m-d H:i:s')));
$this->em->persist($user);
$this->em->flush();
}
return $user;
}
/**
* @return \KnpU\OAuth2ClientBundle\Client\OAuth2Client
*/
private function getGoogleClient()
{
return $this->clientRegistry->getClient('google');
}
/**
* Returns a response that directs the user to authenticate.
*
* This is called when an anonymous request accesses a resource that
* requires authentication. The job of this method is to return some
* response that "helps" the user start into the authentication process.
*
* Examples:
* A) For a form login, you might redirect to the login page
* return new RedirectResponse('/login');
* B) For an API token authentication system, you return a 401 response
* return new Response('Auth header required', 401);
*
* @param Request $request The request that resulted in an AuthenticationException
* @param \Symfony\Component\Security\Core\Exception\AuthenticationException $authException The exception that started the authentication process
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function start(Request $request, \Symfony\Component\Security\Core\Exception\AuthenticationException $authException = null)
{
return new RedirectResponse('/login');
}
/**
* Called when authentication executed, but failed (e.g. wrong username password).
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the login page or a 403 response.
*
* If you return null, the request will continue, but the user will
* not be authenticated. This is probably not what you want to do.
*
* @param Request $request
* @param \Symfony\Component\Security\Core\Exception\AuthenticationException $exception
*
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function onAuthenticationFailure(Request $request, \Symfony\Component\Security\Core\Exception\AuthenticationException $exception)
{
// TODO: Implement onAuthenticationFailure() method.
}
/**
* Called when authentication executed and was successful!
*
* This should return the Response sent back to the user, like a
* RedirectResponse to the last page they visited.
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @param Request $request
* @param \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token
* @param string $providerKey The provider (i.e. firewall) key
*
* @return void
*/
public function onAuthenticationSuccess(Request $request, \Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token, $providerKey)
{
// TODO: Implement onAuthenticationSuccess() method.
}
}
+84
View File
@@ -0,0 +1,84 @@
<?php
namespace App\Security;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\User;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
class UserProvider implements UserProviderInterface
{
private $entityManager;
/**
* UserProvider constructor.
* @param EntityManagerInterface $entityManager
* @internal param Client $httpClient
* @internal param UserOptionService $userOptionService
* @internal param ProjectService $projectService
* @internal param SessionService $sessionService
* @internal param Session $session
* @internal param UserOptionService $userOptionsService
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* Loads the user for the given username.
*
* This method must throw UsernameNotFoundException if the user is not
* found.
*
* @param string $username The username
*
* @return UserInterface
*
* @throws \Doctrine\ORM\NonUniqueResultException
*/
public function loadUserByUsername($username)
{
return $this->entityManager->createQueryBuilder('u')
->where('u.email = :email')
->setParameter('email', $username)
->getQuery()
->getOneOrNullResult();
}
/**
* Refreshes the user.
*
* It is up to the implementation to decide if the user data should be
* totally reloaded (e.g. from the database), or if the UserInterface
* object can just be merged into some internal array of users / identity
* map.
*
* @param UserInterface $user
* @return UserInterface
*
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $user;
}
/**
* Whether this provider supports the given user class.
*
* @param string $class
*
* @return bool
*/
public function supportsClass($class)
{
return $class === 'App\Security\User';
}
}
+33
View File
@@ -90,9 +90,36 @@
"egulias/email-validator": { "egulias/email-validator": {
"version": "2.1.14" "version": "2.1.14"
}, },
"guzzlehttp/guzzle": {
"version": "6.5.2"
},
"guzzlehttp/promises": {
"version": "v1.3.1"
},
"guzzlehttp/psr7": {
"version": "1.6.1"
},
"jdorn/sql-formatter": { "jdorn/sql-formatter": {
"version": "v1.2.17" "version": "v1.2.17"
}, },
"knpuniversity/oauth2-client-bundle": {
"version": "1.20",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "master",
"version": "1.20",
"ref": "80acc9223a205cbf5d9828fd616c82a374d281dd"
},
"files": [
"config/packages/knpu_oauth2_client.yaml"
]
},
"league/oauth2-client": {
"version": "2.4.1"
},
"league/oauth2-google": {
"version": "3.0.2"
},
"monolog/monolog": { "monolog/monolog": {
"version": "1.25.3" "version": "1.25.3"
}, },
@@ -123,12 +150,18 @@
"psr/container": { "psr/container": {
"version": "1.0.0" "version": "1.0.0"
}, },
"psr/http-message": {
"version": "1.0.1"
},
"psr/link": { "psr/link": {
"version": "1.0.0" "version": "1.0.0"
}, },
"psr/log": { "psr/log": {
"version": "1.1.2" "version": "1.1.2"
}, },
"ralouphie/getallheaders": {
"version": "3.0.3"
},
"sensio/framework-extra-bundle": { "sensio/framework-extra-bundle": {
"version": "5.2", "version": "5.2",
"recipe": { "recipe": {
+1
View File
@@ -3,6 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>{% block title %}Welcome!{% endblock %}</title> <title>{% block title %}Welcome!{% endblock %}</title>
<link rel="stylesheet" href="https://unpkg.com/purecss@1.0.1/build/pure-min.css" integrity="sha384-oAOxQR6DkCoMliIh8yFnu25d7Eq/PHS21PClpwjOTeU2jRSq11vu66rf90/cZr47" crossorigin="anonymous">
{% block stylesheets %}{% endblock %} {% block stylesheets %}{% endblock %}
</head> </head>
<body> <body>
+35 -1
View File
@@ -1,5 +1,39 @@
{% extends 'base.html.twig' %} {% extends 'base.html.twig' %}
{% block body %} {% block body %}
<h1>Your lucky number is {{ number }}</h1>
<div style="margin: 0 64px; max-width: 680px;">
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<li class="pure-menu-item">
{% if is_granted('ROLE_USER') %}
<a href="#" class="pure-menu-link"><div style="align-items: center; display: flex;">
<img src="{{ app.user.avatar }}" width="25px" height="25px" style="padding: 4px"/>
<div>{{ app.user.name }}</div>
</div>
</a>
{% else %}
<a href="{{ path('connect_google') }}" class="pure-menu-link">
Вход через Google
</a>
{% endif %}
</li>
{% if is_granted('ROLE_USER') %}
<li class="pure-menu-item"><a href="{{ path('app_logout') }}" class="pure-menu-link">Выход</a></li>
{% endif %}
</ul>
</div>
<div class="content">
<h2 id="responsive-images" class="content-subhead">Content<a href="#responsive-images" class="content-link" title="Heading anchor"></a></h2>
<p>
Content
</p>
</div>
<h1>Your lucky number is {{ number }}</h1>
</div>
{% endblock %} {% endblock %}