avris / micrus-social
Social login handler for the Micrus framework
Requires
- abraham/twitteroauth: ^0.6.4
- avris/micrus: ^3.0
- avris/micrus-annotations: ^3.0
- avris/micrus-assetic: ^3.0
- avris/micrus-doctrine: ^3.0
- avris/micrus-forms: ^3.1
- avris/micrus-imagine: ^3.0
- avris/micrus-mailer: ^3.0
- avris/micrus-twig: ^3.0
- facebook/php-sdk-v4: ^5.1
- google/apiclient: ^2.0
- guzzlehttp/guzzle: ^6.2
README
This is a module for Micrus framework that provides an implementation of user registration, login and account management, including social media login (OAuth2).
For an example implentation, check out Dibsy (git repo).
Currently it supports:
- Google Plus
- Github
- Gitlab
- Microsoft
- Yahoo
To install this module, open the file app/Config/modules.yml
and add:
- Avris\Micrus\Social\SocialModule
Then run:
composer require avris/micrus-social
The module uses:
Basic login
The module defines two abstract models: BaseUser
and BaseAuthenticator
.
You need to extend them in App\Model
namespace.
<?php
namespace App\Model;
use Avris\Micrus\Social\Model\BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class User extends BaseUser
{
// project specific logic here
}
<?php
namespace App\Model;
use Avris\Micrus\Social\Model\BaseAuthenticator;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Authenticator extends BaseAuthenticator
{
// project specific logic here
}
The same goes for the controller. To activate it, you need to "bring" it
to the App\Controller
namespace,where you can extend it as you wish:
<?php
namespace App\Controller;
use Avris\Micrus\Social\SocialController;
use Avris\Micrus\Annotations as M;
class UserController extends SocialController
{
}
Now all you need to do, is to render links to login/account/logout:
{% include 'User/indicator' %}
The module will provide all the necessary controllers, forms, views, translations (only English so far) and sending emails (see: Micrus Mailer).
You can customize almost everything, mainly by creating your own templates in App\View\Crud
,
extending the above models and controller and adding your translations in App\Locale
.
Settings
In config.yml
you can change the list of enabled sources:
social:
sources: [facebook, google, twitter]
assertHasMethodLeft: false
When the option assertHasMethodLeft
is set, SocialModule will disallow the user
to revoke their permissions for a social login, if they don't have any alternative
login option enabled (like password).
Social media login
You will be asked for the app credentails for the OAuth providers. You can get them at:
- developers.facebook.com
- dev.twitter.com
- console.developers.google.com
- github.com/settings/developers
- gitlab.com/profile/applications
- www.linkedin.com/secure/developer
- apps.dev.microsoft.com
- developer.yahoo.com/oauth
Handler
This module will take care of the communication between your app and OAuth providers, but you will have to handle the result (persist a user in database, log them in). To do it, declare a handler service like that:
userManager:
class: App\Service\User\UserManager
parameters: [ '@orm.entityManager', '@securityManager', '@request']
tags: [defaultParameters]
Example content:
<?php
namespace App\Service;
use App\Model\Authenticator;
use App\Model\User;
use Avris\Micrus\Controller\Http\Request;
use Avris\Micrus\Model\User\AuthenticatorInterface;
use Avris\Micrus\Social\SocialLoginException;
use Avris\Micrus\Social\SocialLoginHandlerInterface;
use Avris\Micrus\Tool\SecurityManager;
use Doctrine\ORM\EntityManager;
class UserManager implements SocialLoginHandlerInterface
{
/** @var EntityManager */
protected $em;
/** @var SecurityManager */
protected $sm;
/** @var Request */
protected $request;
public function __construct(
EntityManager $em,
SecurityManager $sm,
Request $request
) {
$this->em = $em;
$this->sm = $sm;
$this->request = $request;
}
public function login(User $user)
{
if (!$user->isActive()) {
$this->request->addFlash('danger', l('entity.User.custom.inactive'));
return 'home';
}
$this->em->persist($user);
$this->em->flush();
$this->sm->login($user);
return 'serverList';
}
public function loginSocial($source, $payload)
{
$user = $this->em->getRepository('Authenticator')->findUserBySocialAuth($source, $payload['id'])
?: new User($payload['email']);
if (!$user->getAuthenticators($source)->count()) {
$user->createAuthenticator($source, $payload);
}
return $this->login($user);
}
public function loginSocialFail(SocialLoginException $e)
{
$this->request->addFlash('danger', l('entity.User.socialLogin.loginFailed', ['%source%' => $e->getSource()]));
return 'home';
}
public function revokeSocial(AuthenticatorInterface $auth)
{
/** @var Authenticator $auth */
$auth->setValid(false);
$this->em->persist($auth);
$this->em->flush();
}
public function updateSocial(AuthenticatorInterface $auth, array $old, array $new)
{
/** @var Authenticator $auth */
$auth->setPayload($new);
$this->em->persist($auth);
}
}
Login buttons
To present a user with a link to social login, use the route socialLogin
with parameter source
(facebook
, twitter
or google
).
You can also display all the available sources like that:
return $this->render([
// ...
'socialSources' => $this->get('socialManager')->getSources(),
]);
and in the view:
<ul>
{% for source in socialSources %}
<li>
<a href="{{ route('socialLogin', {source: source}) }}">
<span class="{{ source.icon }}"></span>
</a>
</li>
{% endfor %}
</ul>
Extend forms
To extend any of the forms defined by the Social Module, simply overwrite the SocialController::FORM_*
constants:
class UserController extends SocialController
{
const FORM_ACCOUNT = 'App\Form\MyAccountForm';
}
Use username
By default, the Social Module uses email as a user identifier. It has however a built-in support for usernames too. If you enable it, selecting a username will be required during registration and the users will be able to log in either using that username or an email.
In config.yml
:
social:
useUsername: true
In App\Model\User
:
<?php
namespace App\Model;
use Avris\Micrus\Social\Model\BaseUser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
*/
class User extends BaseUser
{
/**
* @var string
* @ORM\Column(type="string", unique=true, nullable=true, length=36)
*/
private $username;
public function __construct($username = null, $email = null)
{
$this->username = $username;
parent::__construct($email);
}
public function getIdentifier()
{
return $this->getUsername();
}
/**
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* @param string $username
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
}
And finally in services.yml
:
userProvider:
class: Avris\Micrus\Social\EmailOrUsernameUserProvider
params: ['@orm']
Copyright
- Author: Andrzej Prusinowski (Avris.it)
- Licence: MIT