Laravel 4 custom Auth - php

First of all sorry about my english, I'll try to do my best.
Im new to Laravel, im trying to implement custom auth throught a SOAP WS, I declare new class that implement UserProviderInterface. I success on implement retrieveByCredentials and validateCredentials methods but since i dont have access to database or global users information i cant implement retrieveByID method. Is there any way to make custom Auth not based on users id's ?
I need:
- Login and validate user throught SOAP WS
- Store User Info returned by WS.
- Remember me functionality
- Secure routes based on logged user and level of access
- Logout
Implemented class:
<?php
namespace Spt\Common\Providers;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserInterface;
class AuthUserProvider implements UserProviderInterface{
private $user;
public function __construct(){
$this->user = null;
}
public function retrieveByID($identifier){
return $this->user;
}
public function retrieveByCredentials(array $credentials){
$client = new \SoapClient('webserviceurl');
$res = $client->Validar_Cliente($credentials);
$res = $res->Validar_ClienteResult;
if($res->infoError->bError === true){
return;
}
$res->id = $res->id_cliente;
$user = new GenericUser((array) $res);
return $user;
}
public function validateCredentials(UserInterface $user, array $credentials){
//Assumed that if WS returned a User is validated
return true;
}
}
I think that re-implement UserProviderInterface its not the solution but i googled and not found other way
Any Idea?

You're almost done, apart from the fact that private variable $user of AuthUserProvider doesn't survive the current http request. If you cannot "retrieve by id" from your web service, I guess the only way is to store the entire user in the session - Laravel itself stores the user's id in the session and the fact that it stores only the id (not the entire user) is one of the reasons why a retrieveByID method is needed.
The following is only to clarify and is untested.
class AuthUserProvider implements UserProviderInterface {
public function retrieveByCredentials(array $credentials) {
$client = new \SoapClient('webserviceurl');
$res = $client->Validar_Cliente($credentials);
$res = $res->Validar_ClienteResult;
if($res->infoError->bError === true) {
return;
}
$res->id = $res->id_cliente;
Session::put('entireuser', $res);
$user = new GenericUser((array) $res);
return $user;
}
public function retrieveByID($identifier) {
$res = Session::get('entireuser');
return new GenericUser((array) $res);
}
// ...
}
If you can't retrieve by id from your web service, I guess you cannot either retrieve by remember token, so it may be impossible for you to implement the "remember me" functionality, unless you store part of users data in a second database (which at that point could be used in place of the session above).

Related

Should I create an interface to unify the way the endpoints forms and outputs the response in an API?

So, I'm building an API architecture and I am struck on the way the programmer will be implementing the output of the API endpoints.
The thing is that there can be different ways to store the response that I'm going to output and I'dont know if it would be worth to make an interface and force the developer to use just one way.
First case, using a class property.
We have a controller that makes a number of actions all based on a resource 'user' and then in a response handler function returns the formed response:
class LogInController implements ResponseInterface{
private $user;
private function setUser(){...};
private function checkThatToTheUser();{...}
function LogInEndpoint(){
$this->setUser();
$this->checkThatToTheUser();
return $this->handledResponse();
}
/**implemented function that doesn't
take parameters as it has access
to the class property that has the response formed*/
function handledResponse(){
$response = [
'user_id' => $this->user->id
];
return $this->APIResponse($response);
};
}
Second case, directly calling to the response manager.
We have a controller that simply outputs some data from the database, which in this cases can be a collection or a collection of collections.
class UserController{
function get(){
$users = User::paginate(20);
return $this->APIReponse($users);
}
function getByID($id){
$user = User::find($id);
return $this->APIReponse($user);
}
}
Third case, we encapsulate all the response generation on a function but having no properties.
In this case we pass the instanciated user to the response handler.
class UserActionsController{
private function get(){
$user = User::find(1);
return $user
}
private function getComplexThings($user){
...
return $user;
}
function getComplextDataEndpoint(){
$user = $this->get();
$user = $this->getComplexThings($user);
return $this->handledResponse($user);
}
function handledResponse($user){
...
return $this->APIResponse($user);
}
}
Should I let this open and let the programmer choose in the moment of the implementation or force the way it gets implemented (properties, parameters, directly outputs, outputs under a response handler...).

How to create Laravel 5.1 Custom Authentication driver?

I am working in Laravel authentication login using socialite. Now I can able to save data of user from socialite. But now I am facing problem how to authenticate user from gmail, github.
After some research I understood that I need to create custom authentication. I googled but all are Laravel 4.1 topics. If any one work on this please provide your answers.
I already read following topics but I didn't got how to do it?
http://laravel.com/docs/5.1/authentication#social-authentication
http://laravel.com/docs/5.1/providers
http://laravel-recipes.com/recipes/115/using-your-own-authentication-driver
http://laravel.io/forum/11-04-2014-laravel-5-how-do-i-create-a-custom-auth-in-laravel-5
Update
public function handleProviderCallback() {
$user = Socialite::with('github')->user();
$email=$user->email;
$user_id=$user->id;
//$authUser = User::where('user_id',$user_id)->where('email', $email)->first();
$authUser = $this->findOrCreateUser($user);
if(Auth::login($authUser, true)) {
return Redirect::to('user/UserDashboard');
}
}
private function findOrCreateUser($user) {
if ($authUser = User::where('user_id',$user->id)->first()) {
return $authUser;
}
return User::create([
'user_id' => $user->id,
'name' => $user->nickname,
'email' => $user->email,
'avatar' => $user->avatar
]);
}
This answer is most suited for Laravel 5.1. Please take care if you
are in some other version. Also keep in mind that IMHO this is a rather advanced level in Laravel, and hence if you don't fully understand what you are doing, you may end up crashing your application. The solution is not end to end correct. This is just a general guideline of what you need to do in order for this to work.
Adding Custom Authentication Drivers In Laravel 5.1
Hint: Laravel documentation for this topic is here.
Hint2: The last link you mentioned is quite useful in my opinion. I learned all of this after reading that link.
http://laravel.io/forum/11-04-2014-laravel-5-how-do-i-create-a-custom-auth-in-laravel-5
Before we start, I would first like to describe the login flow which will help you understand the process. Laravel uses a driver to connect to the database to fetch your records. Two drivers come pre-bundled with laravel - eloquent & database. We want to create a third so that we can customize it to our needs.
Illuminate\Auth\Guard inside your vendor folder is the main file which has code for the user to log in and log out. And this file mainly uses two Contracts (or interfaces) that we need to override in order for our driver to work. From Laravel's own documentation read this:
The Illuminate\Contracts\Auth\UserProvider implementations are only
responsible for fetching a Illuminate\Contracts\Auth\Authenticatable
implementation out of a persistent storage system, such as MySQL,
Riak, etc. These two interfaces allow the Laravel authentication
mechanisms to continue functioning regardless of how the user data is
stored or what type of class is used to represent it.
So the idea is that for our driver to work we need to implement Illuminate\Contracts\Auth\UserProvider and Illuminate\Contracts\Auth\Authenticatable and tell Laravel to use these implementations instead of the defaults.
So let's begin.
Step 1:
Choose a name for your driver. I name mine socialite. Then in your config/auth.php, change the driver name to socialite. By doing this we just told laravel to use this driver for authentication instead of eloquent which is default.
Step 2:
In your app/Provider/AuthServiceProvider in the boot() method add the following lines:
Auth::extend('socialite', function($app) {
$provider = new SocialiteUserProvider();
return new AuthService($provider, App::make('session.store'));
});
What we did here is:
We first used Auth facade to define the socialite driver.
SocialiteUserProvider is an implementation of UserProvider.
AuthService is my extension of Guard class. The second parameter this class's constructor takes is the session which laravel uses to get and set sessions.
So we basically told Laravel to use our own implementation of Guard class instead of the default one.
Step 3:
Create SocialiteUserProvider. If you read the Laravel's documentation, you will understand what each of these methods should return. I have created the first method as a sample. As you can see, I use my UserService class to fetch results. You can fetch your own results however you want to fetch them. Then I created an User object out of it. This User class implements the Illuminate\Contracts\Auth\Authenticatable contract.
<?php
namespace App\Extensions;
use App\User;
use App\Services\UserService;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
class SocialiteUserProvider implements UserProvider
{
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
public function retrieveById($identifier)
{
$result = $this->userService->getUserByEmail($identifier);
if(count($result) === 0)
{
$user = null;
}
else
{
$user = new User($result[0]);
}
return $user;
}
public function retrieveByToken($identifier, $token)
{
// Implement your own.
}
public function updateRememberToken(Authenticatable $user, $token)
{
// Implement your own.
}
public function retrieveByCredentials(array $credentials)
{
// Implement your own.
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
// Implement your own.
}
}
Step 4:
Create User class which implements the Authenticatable. This class has to implement this interface because the Guard class will use this class to get values.
<?php
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
class User implements Authenticatable
{
protected $primaryKey = 'userEmail';
protected $attributes = [];
public function __construct(array $attributes)
{
$this->attributes = $attributes;
}
public function getUserAttributes()
{
return $this->attributes;
}
public function getAuthIdentifier()
{
return $this->attributes[$this->primaryKey];
}
public function getAuthPassword()
{
// Implement your own.
}
public function getRememberToken()
{
// Implement your own.
}
public function setRememberToken($value)
{
// Implement your own.
}
public function getRememberTokenName()
{
// Implement your own.
}
}
Step 5:
Finally create the AuthService class that will call the Guard methods. This is my own implementation. You can write your own as per your needs. What we have done here is extended the Guard class to implement two new functions which are self explanatory.
<?php
namespace App\Services;
use Illuminate\Auth\Guard;
class AuthService extends Guard
{
public function signin($email)
{
$credentials = array('email' => $email);
$this->fireAttemptEvent($credentials, false, true);
$this->lastAttempted = $user = $this->provider->retrieveById($email);
if($user !== null)
{
$this->login($user, false);
return true;
}
else
{
return false;
}
}
public function signout()
{
$this->clearUserDataFromStorage();
if(isset($this->events))
{
$this->events->fire('auth.logout', [$this->user()]);
}
$this->user = null;
$this->loggedOut = true;
}
}
Step 6: Bonus Step
Just to complete my answer, I will also explain the structure that UserService class expects. First lets understand what this class does. In our above steps we created everything to let laravel know how to use our authentication driver, instead of theirs. But we still haven't told laravel that how should it get the data. All we told laravel that if you call the userService->getUserByEmail($email) method, you will get your data. So now we simply have to implement this function.
E.g.1 You are using Eloquent.
public function getUserByEmail($email)
{
return UserModel::where('email', $email)->get();
}
E.g.2 You are using Fluent.
public function getUserByEmail($email)
{
return DB::table('myusertable')->where('email', '=', $email)->get();
}
Update: 19 Jun 2016
Thank you #skittles for pointing out that I have not clearly shown where the files should be placed. All the files are to be placed as per the namespace given. E.g. if the namespace is App\Extensions and the class name is SocialiteUserProvider then location of file is App\Extensions\SocialiteUserProvider.php. The App directory in laravel is the app folder.
Good tutorial for setting up laravel socialite here: https://mattstauffer.co/blog/using-github-authentication-for-login-with-laravel-socialite
Auth::login doesn't return a boolean value you can use attempt to do a Auth::attempt
if(Auth::login($authUser, true)) {
return Redirect::to('user/UserDashboard');
}
Follow the tutorial and do this, and just have middleware configured on the home route
$authUser = $this->findOrCreateUser($user);
Auth::login($authUser, true);
return Redirect::to('home');

Storing a model instance as a service during the session

I want to access to profile of the current user across the application (read/write). The user profile is an in instance of User model. Is it possible to store it on session as a service? If not, what is best practice?
Here is my login code. (ajax-based login)
function loginAction()
{
$this->view->disable();
{
$request = (array)$this->request->getJsonRawBody();
$user = User::findFirstByUsername($request['username']);
if (password_verify($request['password'], $user->password)) {
$userModel = User::findFirst('username="'.$request['username'].'"');
$this->getDI()['session']->set('auth', $user->id);
$this->user = $user;
jsonResponse($user);
} else {
http_response_code(401);
jsonResponse(['message' => 'invalid']);
}
}
}
There is several ways to achieve that. Let me share with you the one I've used in my own project...
First I've created a Component to deal with authentication related stuff such as checking the current session status (guest, user, admin), storing the current user specs, authentication procedures, etc.
namespace MyApp\Components;
use Phalcon\Mvc\User\Component as PhComponent;
class Authentication extends PhComponent
{
// ...
}
Then, I've registered this component in the main App's DI container:
$di->setShared('authentication', 'MyApp\Components\Authentication');
So I can use from my controllers, views, etc. Like:
function homeAction()
{
//...
if($this->authentication->isGuest()) {
//...
}
Finally to store data using the session. Phalcon provide a persistent session bag that you can use to easily store a serialized version of the model in the current session:
class Authentication extends PhComponent
{
// ...
function authenticate($username, $password)
{
// ... Authentication logic
if($validCredentials) {
$this->persistent->currentUser = $userModel;
}
// ...
}
}

Doctrine 2 - Get Entity manager from class

I can't figure out how it is best to get the Doctrine Entity Manager from my service layers, and template controller..
I thinking of making a singleton so i always can get the Entity manager, but is it the right way to do it?
Updated: I'll take an example
class Auth
{
const USER_ENTITY_NAME = 'Entities\User';
private $isVerified = FALSE;
public static function login($email, $password, $em, $rememberMe = false)
{
if(empty($email) OR empty($password))
{
// new login response
}
if($user = (self::getUser($email, $password, $em) !== null))
{
$sreg = SessionRegistry::instance();
$sreg->set("user_id", $user->getId());
}
return $user;
}
public static function getUser($email, $password, $em)
{
return $em->getRepository(
USER_ENTITY_NAME );
}
What i cant figure out is where i should get the user from? so i doesn't have to send the entity manager as an parameter.
Choose dependency injection over singleton.
I don't know which environment are you using Doctrine in, but I assume it being MVC - then any Controller should have access to the entity manager, either by passing it as a constructor argument, either by injecting it with a setter.
This way you can fetch stuff from the controller, and pass it to the Auth class eventually.
Anyway I think that authorization doesn't need an external class - I'd just write a loginAction method in a controller, get username and password from HTTP request and make the usual considerations [fetch the user / check if password is right], then store something in session in case of succesful login.

how to Use zend_auth as a plugin

I'm working on my first user login in Zend Framework, but I'm a little confused with Zend_Auth. All the articles I read about it use it directly in the controller. But to me, it makes more sense, to work as a plugin
What do you guys think?
You can use it as a plugin, the only downside is that if you initialize the plugin in your bootstrap, then the plugin will be executed for every controller and action, since it would have to run before your controller.
You could extend Zend_Auth and add extra methods to set up the auth adapter and manage the storage, and then you can just call Your_Custom_Auth::getInstance() to get the auth instance and then you can check for auth in the preDispatcth() part of your controllers that need auth.
This way you can easily work with zend_auth in multiple places with less code
<?php
class My_User_Authenticator extends Zend_Auth
{
protected function __construct()
{}
protected function __clone()
{}
public static function getInstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
// example using zend_db_adapter_dbtable and mysql
public static function getAdapter($username, $password)
{
$db = Zend_Controller_Front::getInstance()
->getParam('bootstrap')
->getResource('db');
$authAdapter = new Zend_Auth_Adapter_DbTable($db,
'accounts',
'username',
'password');
$authAdapter->setIdentity($username)
->setCredential($password)
->setCredentialTreatment(
'SHA1(?)'
);
return $authAdapter;
}
public static function updateStorage($storageObject)
{
self::$_instance->getStorage()->write($storageObject);
}
}
// in your controllers that should be fully protected, or specific actions
// you could put this in your controller's preDispatch() method
if (My_User_Authenticator::getInstance()->hasIdentity() == false) {
// forward to login action
}
// to log someone in
$auth = My_User_Authenticator::getInstance();
$result = $auth->authenticate(
My_User_Authenticator::getAdapter(
$form->getValue('username'),
$form->getValue('password'))
);
if ($result->isValid()) {
$storage = new My_Session_Object();
$storage->username = $form->getValue('username');
// this object should hold the info about the logged in user, e.g. account details
My_User_Authenticator::getInstance()->updateStorage($storage); // session now has identity of $storage
// forward to page
} else {
// invalid user or pass
}
Hope that helps.
"Plugin" in ZF doesn't only mean "front controller plugin", also Action helpers, view helpers...
ZF guru Matthew Weier O'Phinney wrote an excellent article about creating action helpers, and guess what ?..
He illustrates it with an Auth widget !
http://weierophinney.net/matthew/archives/246-Using-Action-Helpers-To-Implement-Re-Usable-Widgets.html
don't forget to read the articles comments, as a lot of interesting Q&A are handled there

Categories