Content
+ ++ Content +
+diff --git a/.env b/.env
index b3ea64e..7581cf4 100644
--- a/.env
+++ b/.env
@@ -29,5 +29,6 @@ APP_SECRET=2a37fd338bcb9eeec4645dd50db620e0
# 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"
# 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 ###
+
diff --git a/composer.json b/composer.json
index ac74db4..0757b19 100644
--- a/composer.json
+++ b/composer.json
@@ -5,6 +5,8 @@
"php": "^7.1.3",
"ext-ctype": "*",
"ext-iconv": "*",
+ "knpuniversity/oauth2-client-bundle": "^1.32",
+ "league/oauth2-google": "^3.0",
"sensio/framework-extra-bundle": "^5.5",
"symfony/apache-pack": "^1.0",
"symfony/asset": "4.4.*",
diff --git a/composer.lock b/composer.lock
index c5d87a5..1bfa45a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d6e8bc8b46d0e946a35999599cf79156",
+ "content-hash": "067b0e9ecd420b1b48945900bf4c8987",
"packages": [
{
"name": "doctrine/annotations",
@@ -1204,6 +1204,195 @@
],
"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",
"version": "v1.2.17",
@@ -1254,6 +1443,181 @@
],
"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",
"version": "1.25.3",
@@ -1698,6 +2062,56 @@
],
"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",
"version": "1.0.0",
@@ -1794,6 +2208,46 @@
],
"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",
"version": "v5.5.3",
diff --git a/config/bundles.php b/config/bundles.php
index 7745edb..00950cb 100644
--- a/config/bundles.php
+++ b/config/bundles.php
@@ -12,4 +12,5 @@ return [
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
+ KnpU\OAuth2ClientBundle\KnpUOAuth2ClientBundle::class => ['all' => true],
];
diff --git a/config/packages/knpu_oauth2_client.yaml b/config/packages/knpu_oauth2_client.yaml
new file mode 100644
index 0000000..fce32af
--- /dev/null
+++ b/config/packages/knpu_oauth2_client.yaml
@@ -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: {}
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index ce69ba7..5b8d00e 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -1,22 +1,23 @@
security:
# 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:
- in_memory: { memory: null }
+ my_provider:
+ entity: { class: App:User, property: username }
+
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: lazy
+ anonymous: ~
+ logout:
+ path: /logout
+ target: /
+ logout_on_user_change: true
- # activate different ways to authenticate
- # https://symfony.com/doc/current/security.html#firewalls-authentication
-
- # 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 }
+ guard:
+ authenticators:
+ - App\Security\GoogleAuthenticator
diff --git a/config/routes.yaml b/config/routes.yaml
index c3283aa..e52801b 100644
--- a/config/routes.yaml
+++ b/config/routes.yaml
@@ -1,3 +1,7 @@
#index:
# path: /
# controller: App\Controller\DefaultController::index
+
+app_logout:
+ path: /logout
+ methods: GET
diff --git a/src/Controller/GoogleController.php b/src/Controller/GoogleController.php
new file mode 100644
index 0000000..498d8f7
--- /dev/null
+++ b/src/Controller/GoogleController.php
@@ -0,0 +1,40 @@
+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');
+ }
+}
\ No newline at end of file
diff --git a/src/Entity/User.php b/src/Entity/User.php
new file mode 100644
index 0000000..1a5080c
--- /dev/null
+++ b/src/Entity/User.php
@@ -0,0 +1,176 @@
+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.
+ *
+ *
+ * public function getRoles()
+ * {
+ * return array('ROLE_USER');
+ * }
+ *
+ *
+ * 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;
+ }
+}
diff --git a/src/Migrations/Version20200111120854.php b/src/Migrations/Version20200111120854.php
new file mode 100644
index 0000000..46351a0
--- /dev/null
+++ b/src/Migrations/Version20200111120854.php
@@ -0,0 +1,35 @@
+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');
+ }
+}
diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php
new file mode 100644
index 0000000..64f692f
--- /dev/null
+++ b/src/Repository/UserRepository.php
@@ -0,0 +1,50 @@
+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()
+ ;
+ }
+ */
+}
diff --git a/src/Security/GoogleAuthenticator.php b/src/Security/GoogleAuthenticator.php
new file mode 100644
index 0000000..4b0a517
--- /dev/null
+++ b/src/Security/GoogleAuthenticator.php
@@ -0,0 +1,129 @@
+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.
+ }
+}
diff --git a/src/Security/UserProvider.php b/src/Security/UserProvider.php
new file mode 100644
index 0000000..5b925fd
--- /dev/null
+++ b/src/Security/UserProvider.php
@@ -0,0 +1,84 @@
+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';
+ }
+}
diff --git a/symfony.lock b/symfony.lock
index 4753282..fc32fcd 100644
--- a/symfony.lock
+++ b/symfony.lock
@@ -90,9 +90,36 @@
"egulias/email-validator": {
"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": {
"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": {
"version": "1.25.3"
},
@@ -123,12 +150,18 @@
"psr/container": {
"version": "1.0.0"
},
+ "psr/http-message": {
+ "version": "1.0.1"
+ },
"psr/link": {
"version": "1.0.0"
},
"psr/log": {
"version": "1.1.2"
},
+ "ralouphie/getallheaders": {
+ "version": "3.0.3"
+ },
"sensio/framework-extra-bundle": {
"version": "5.2",
"recipe": {
diff --git a/templates/base.html.twig b/templates/base.html.twig
index 043f42d..c61820a 100644
--- a/templates/base.html.twig
+++ b/templates/base.html.twig
@@ -3,6 +3,7 @@