Podio API - Session Management class error in accessing tokens in Redis - podio

I'm trying to use Session Management for API calls, so I don't trigger Auth class function everytime my script run. I mostly used App ID authentication so I used the sample provided for Redis.
However, I'm getting an error "Fatal error: Uncaught Error: Cannot access self:: when no class scope is active in /var/www/html/authcheck.php:22 Stack trace: #0 {main} thrown in /var/www/html/authcheck.php on line 22"
The code in line 22 is this - Podio::$oauth = self::$session_manager->get(Podio::$auth_type);
Here's the PHP Script for Session manager class:
Filename: SessionManager.php
<?php
require ('podio/podio_lib/PodioAPI.php');
require ('predis/autoload.php');
class PodioRedisSession {
/**
* Create a pointer to Redis when constructing a new object
*/
public function __construct() {
$this->redis = new Predis\Client();
}
/**
* Get oauth object from session, if present. We use $auth_type as
* basis for the cache key.
*/
public function get($auth_type = null) {
// If no $auth_type is set, just return empty
// since we won't be able to find anything.
if (!$auth_type) {
return new PodioOauth();
}
$cache_key = "podio_cache_".$auth_type['type']."_".$auth_type['identifier'];
// Check if we have a stored session
if ($this->redis->exists($cache_key)) {
// We have a session, create new PodioOauth object and return it
$cached_value = $this->redis->hgetall($cache_key);
return new PodioOAuth(
$cached_value['access_token'],
$cached_value['refresh_token'],
$cached_value['expires_in'],
array("type"=>$cached_value['ref_type'], "id"=>$cached_value['ref_id'])
);
}
// Else return an empty object
return new PodioOAuth();
}
/**
* Store the oauth object in the session. We ignore $auth_type since
* it doesn't work with server-side authentication.
*/
public function set($oauth, $auth_type = null) {
$cache_key = "podio_cache_".$auth_type['type']."_".$auth_type['identifier'];
// Save all properties of the oauth object in redis
$this->redis->hmset = array(
'access_token' => $oauth->access_token,
'refresh_token' => $oauth->refresh_token,
'expires_in' => $oauth->expires_in,
'ref_type' => $oauth->ref["type"],
'ref_id' => $oauth->ref["id"],
);
}
}
?>
Filename: authcheck.php
<?php
require ('podio/podio_lib/PodioAPI.php');
include ('SessionManager.php');
$client_id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$app_id = "xxxxxxxxxxx";
$app_token = "xxxxxxxxxxxxxxxxxxx";
Podio::setup($client_id, $client_secret, array(
"session_manager" => "PodioRedisSession"
));
// podio-php will attempt to find a session automatically, but will fail
because
// it doesn't know which $auth_type to use.
// So we must attempt to locate a session manually.
Podio::$auth_type = array(
"type" => "app",
"identifier" => $app_id
);
Podio::$oauth = self::$session_manager->get(Podio::$auth_type);
// Now we can check if anything could be found in the cache and
// authenticate if it couldn't
if (!Podio::is_authenticated()) {
// No authentication found in session manager.
// You must re-authenticate here.
Podio::authenticate_with_app($app_id, $app_token);
} else {
//echo "<pre>".print_r($_SESSION, true)."</pre>";
echo "You already authenticated!";
}
// // We can safely switch to another app now
// // First attempt to get authentication from cache
// // If that fails re-authenticate
// Podio::$auth_type = array(
// "type" => "app",
// "identifier" => $another_app_id
// );
// Podio::$oauth = self::$session_manager->get(Podio::$auth_type);
// if (!Podio::is_authenticated()) {
// // No authentication found in session manager.
// // You must re-authenticate here.
// Podio::authenticate_with_app($another_app_id, $another_app_token);
// }
?>

Hi opted not to use redis instead I used session and PDO Mysql on storing podio auth.

Related

Laravel /broadcasting/auth Always forbidden with 403 Error

I tried many solutions but no one works for me
I've installed Laravel echo and pusher js and Pusher/Pusher
#bootstrap.js
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true,
});
#.env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=my_id
PUSHER_APP_KEY=my_key
PUSHER_APP_SECRET=my_secret
PUSHER_APP_CLUSTER=eu
my event file NewMessage
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(Message $message)
{
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('messages.'. $this->message->to);
}
public function broadcastWith()
{
return ["message" => $this->message];
}
}
channel.php
Broadcast::channel('messages.{id}', function ($user, $id) {
return $user->id === (int) $id;
});
Vue App JS code
mounted(){
Echo.private(`messages${this.user.id}`)
.listen('NewMessage', (e) => {
this.handleIncoming(e.message)
});
},
methods:{
saveNewMessage(msg){
this.messages.push(msg);
},
handleIncoming(message){
if(this.selectedContact && message.from == this.selectedContact.id ){
this.saveNewMessage(message);
return;
}
alert(message.text);
}
}
Api.php
Route::post('/conversation/send', 'Api\ContactController#sendNewMessage');
Contact Controller
public function sendNewMessage(Request $request)
{
$message = Message::create([
'from' => $request->sender_id,
'to' => $request->receiver_id,
'text' => $request->text
]);
broadcast(new NewMessage($message));
return response()->json($message);
}
I also read the official documentation everything is going good but I didn't figure out why, it's a throwing error. Have any idea?
I figure out why it is every time shows auth forbidden or doesn't display auth
Solution:
you need to double-check your PUSHER_APP_KEY because if it is not set correctly, it will through error because our stream not connected with pusher
PUSHER_APP_KEY="PUT KEY HERE"
If you are very sure that your app key is correct then go to the Network tab and click on your pusher app key which like e70ewesdsdssew0
If it is displaying the result like this
{"event":"pusher:connection_established","data":"{\"socket_id\":\"131139.31305364\",\"activity_timeout\":120}"}
your API key is good
if it not correct it will display an error like this
{"event":"pusher:error","data":{"code":4001,"message":"App key 3fdsfdfsdfsd not in this cluster. Did you forget to specify the cluster?"}}
Also, don't forget to put the cluster key
PUSHER_APP_CLUSTER=eu

About the implementation of Remember Me using AuthenticationPlugin's Cookie Authenticator

I use CakePHP's AuthenticationPlugin. I was trying to implement RememberMe functionality into this.
I found the following article when I was reading the Cakephp documentation.
Cookie Authenticator aka “Remember Me”
However, the documentation here is difficult for me to understand. I have no idea what to do with it.
I've successfully implemented EncryptedCookieMiddleware. I have no idea what to do after that.
I don't know how to use rememberMeField, how to use fields and how to use cookies.
$this->Authentication->rememberMeField
$this->Authentication->fields
I tried to see if I could use it like these, but it was still no good.
Please let me know how to use these.
Also, do you know of any RememberMe tutorials?
How do I implement it?
Sorry. Please help me...
// in config/app.php
'Security' => [
.....
'cookieKey' => env('SECURITY_COOKIE_KEY', 'AnyString'), // <- add
],
// in src/Application.php
use Cake\Http\Middleware\EncryptedCookieMiddleware; // <- add
// in middleware()
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$cookies = new EncryptedCookieMiddleware( // <- add
['mail', 'password'],
Configure::read('Security.cookieKey')
);
$middlewareQueue
// . . .
->add($cookies) // <-add
->add(new AuthenticationMiddleware($this));
So far I've been able to implement it myself. I'm confident.
The problem is after this. We have no idea what to do with it...
A Remember me checkbox was implemented in the template Form.
$this->request->getData('rememberMe'); to get it.
If this is 1, the checkbox was pressed.
// in src/Controller/UsersController
public function login()
{
$this->request->allowMethod(['get', 'post']);
if ($this->request->is('post')) {
$result = $this->Authentication->getResult();
// If the user is logged in, whether POST or GET, we will redirect
$requestGetData = $this->request->getData('rememberMe');
if ($requestGetData['rememberMe'] == 1){
$this->Authentication->cookie['name'] = $requestGetData['mail'];
$this->Authentication->cookie['name'] = $requestGetData['password']
}
if ($result->isValid()) {
$redirect = $this->request->getQuery('redirect', [
'controller' => 'Stores',
'action' => 'index',
]);
return $this->redirect($redirect);
}
// If the user fails to authenticate after submitting, an error is displayed.
if (!$result->isValid()) {
$this->Flash->error(__('Your email address or password is incorrect.'));
}
}
$title = $this->config('Users.title.login');
$message = $this->config('Users.message.login');
$this->set(compact('login_now', 'title', 'message'));
}
I know that's not true. But I tried to implement something like this just in case.
Please help me!
Changed around the login.
public function login()
{
$this->request->allowMethod(['get', 'post']);
if ($this->request->is('post')) {
$result = $this->Authentication->getResult();
$requestData = $this->request->getData();
if ($result->isValid()) {
$redirect = $this->request->getQuery('redirect', [
'controller' => 'Stores',
'action' => 'index',
]);
$this->Authentication->getAuthenticationService()->loadAuthenticator( 'Authentication.Cookie', [
'fields' => ['mail', 'password']
]
);
return $this->redirect($redirect);
}
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('Your email address or password is incorrect.'));
}
}
$title = $this->config('Users.title.login');
$message = $this->config('Users.message.login');
$this->set(compact('title', 'message'));
}
You're not supposed to load authenticators in your controllers, authentication happens at middleware level, before any of your controllers are being invoked.
The cookie authenticator is ment to be loaded and configured just like any other authenticator, that is where you create the authentication service, usually in Application::getAuthenticationService() in src/Application.php.
By default the field in the form must be remember_me, not rememberMe, that is unless you would configure the cookie authenticator's rememberMeField option otherwise.
Furthermore the default cookie name of the cookie authenticator is CookieAuth, so if you wanted to encrypt it, you'd have to use that name in the EncryptedCookieMiddleware config accordingly.
tl;dr
Remove all cookie related code from your controller, and load the authenticator in your Application::getAuthenticationService() method:
use Authentication\Identifier\IdentifierInterface;
// ...
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService();
// ...
// The cookie authenticator should be loaded _after_ the session authenticator,
// and _before_ other authenticators like the form authenticator
$service->loadAuthenticator('Authentication.Cookie', [
// 'rememberMeField' => 'custom_form_field_name', // if you want to change the default
'fields' => [
IdentifierInterface::CREDENTIAL_USERNAME => 'mail',
IdentifierInterface::CREDENTIAL_PASSWORD => 'password',
],
]);
// ...
return $service;
}
set the authentication cookie name in the EncryptedCookieMiddleware config:
$cookies = new EncryptedCookieMiddleware(
['CookieAuth'],
Configure::read('Security.cookieKey')
);
and change the field name in your form to remember_me if you're using the cookie authenticator's defaults:
echo $this->Form->control('remember_me', [
'type' => 'checkbox'
]);
That's all that should be required, if you tick the checkbox in your login form, then the authentication middleware will set a cookie after successful authentication accordingly, and it will pick up the cookie if it's present on a request and no other authenticator successfully authenticates the request first (like the session authenticator for example).

Authentication in laravel

I am making api in laravel. I am using the database that is already built and is live. That system uses md5 with salt values.
I want to do authentication for that system . how should do i have to do?
My source code :
public function authenticate(Request $request)
{
$email = $request->input('email');
$password = md5('testpassword' . 'saltvaluehere');
try {
//
// attempt to verify the credentials and create a token for the user
if (!$token = JWTAuth::attempt([
'email' => $email,
'pass' => $password
])
) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// all good so return the token
return response()->json(compact('token'));
}
In core php these authentication is done by:
$getpass = $mydb->CleanString($_POST['password']);
$getusername = $mydb->CleanString($_POST['username']);
$dbpass = $mydb->md5_decrypt($mydb->getValue("pass","tbl_admin","username = '".$getusername."'"), SECRETPASSWORD);
if($dbpass == $getpass){
return 'success full login';
}
above code doesnot give same value of hash, so i am not being able to authenticate in system.
Edited:
I have got the password that matched with database but token is not bieng generated.
here is my code:
public function authenticate(Request $request)
{
$email = $request->input('email');
$password = $request->input('password');
$password = md5($password);
try {
//
// attempt to verify the credentials and create a token for the user
if (!$token = JWTAuth::attempt([
'email' => $email,
'password' => $password
])
){
//return response()->json(compact('token'));
return response()->json(['error' => 'invalid_credentials','_data'=>[$password,$email]], 401);
}
} catch (JWTException $e) {
// something went wrong whilst attempting to encode the token
return response()->json(['error' => 'could_not_create_token'], 500);
}
// all good so return the token
return response()->json(compact('token'));
}
can anybody tell me the reason why is token not being generated and why is it saying invalid credintials. as it shows the password and email of database of encrypted form.
This is a situation I've dealt with and I have foss code to give as a proof of concept.
Essentially, I added another password field for old passwords. I imported users with password_legacy set to a JSON object of old password data, in my case:
{ 'hasher' : 'algo', 'hash' : '#####', 'salt' : 'salt here' }
Then, I used a modified user service provider so that authentication checked for password_legacy if password was null. It then used the Illuminate Hasher contract as a base and constructed a new instance of a class (dynamically, using the hasher property, so for instance a app\Services\Hashing\AlgoHasher) and then used that for authentication instead of the default system.
If it did succeed, I bcrypt'd the password, set password and unsetpassword_legacy. This upgraded the password to the much higher standard of security that bcrypt offered.
Migration code for new field:
https://github.com/infinity-next/infinity-next/blob/ccb01c753bd5cedd75e03ffe562f389d690de585/database/migrations_0_3_0/2015_06_12_181054_password_legacy.php
Modified user provider:
https://github.com/infinity-next/infinity-next/blob/ccb01c753bd5cedd75e03ffe562f389d690de585/app/Providers/EloquentUserProvider.php
Hasher contract for Vichan (md5+salt):
https://github.com/infinity-next/infinity-next/blob/ccb01c753bd5cedd75e03ffe562f389d690de585/app/Services/Hashing/VichanHasher.php
Relevant user code:
https://github.com/infinity-next/infinity-next/blob/ccb01c753bd5cedd75e03ffe562f389d690de585/app/User.php#L124-L165
Hope that helps!

Yii 2 RESTful API authenticate with OAuth2 (Yii 2 advanced template)

REST API is working without authentication methods. Now i wanted to authenticate REST API with OAuth2 authentication for API requests via mobile application. I tried with yii2 guide, but it didn't work for me.
basically mobile user need to be login with username & password, if a username and password are correct, user need to be login and further API request need to be validate with token.
Do i need to create custom OAuth 2 client like this ?
Creating your own auth clients
access_token field in user table is empty. do i need to save it manually ?
how to return access_token as a respond?
is there any reason for user all three methods(HttpBasicAuth, HttpBearerAuth, QueryParamAuth) at once, why? how?
my application folder structure looks like below.
api
-config
-modules
--v1
---controllers
---models
-runtime
-tests
-web
backend
common
console
environments
frontend
api\modules\v1\Module.php
namespace api\modules\v1;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'api\modules\v1\controllers';
public function init()
{
parent::init();
\Yii::$app->user->enableSession = false;
}
}
api\modules\v1\controllers\CountryController.php
namespace api\modules\v1\controllers;
use Yii;
use yii\rest\ActiveController;
use common\models\LoginForm;
use common\models\User;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
/**
* Country Controller API
*
* #author Budi Irawan <deerawan#gmail.com>
*/
class CountryController extends ActiveController
{
public $modelClass = 'api\modules\v1\models\Country';
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
//'class' => HttpBasicAuth::className(),
'class' => CompositeAuth::className(),
'authMethods' => [
HttpBasicAuth::className(),
HttpBearerAuth::className(),
QueryParamAuth::className(),
],
];
return $behaviors;
}
}
common\models\User.php
namespace common\models;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
class User extends ActiveRecord implements IdentityInterface
{
const STATUS_DELETED = 0;
const STATUS_ACTIVE = 10;
public static function tableName()
{
return '{{%user}}';
}
public function behaviors()
{
return [
TimestampBehavior::className(),
];
}
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_ACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
];
}
public static function findIdentity($id)
{
return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
}
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['access_token' => $token]);
}
}
user table
id
username
auth_key
password_hash
password_reset_token
email
status
created_at
access_token
access_token was added after migrate user table
I'm using JWT for validating the request. Basically JWT is a token which also contain information about a user, and about the token itself such as the validity and the expiration time of the token. You can read more about JWT here.
The flow of my application is like this:
First, when a user logged in, create a JWT for the user
$key = base64_decode('some_random_string');
$tokenId = base64_encode(mcrypt_create_iv(32));
$issuedAt = time();
$notBefore = $issuedAt + 5;
$expire = $notBefore + 1800;
$user = User::findByEmail($email);
$data = [
'iss' => 'your-site.com',
'iat' => $issuedAt,
'jti' => $tokenId,
'nbf' => $notBefore,
'exp' => $expire,
'data' => [
'id' => $user->id,
'username' => $user->username,
//put everything you want (that not sensitive) in here
]
];
$jwt = JWT::encode($data, $key,'HS256');
return $jwt;
Then, the client (e.g the mobile app) must provide the token in every request via Authorization header. The header will look like this:
Authorization:Bearer [the JWT token without bracket]
In the User model, add a method like this for validating the token:
public static function findIdentityByAccessToken($token, $type = null) {
$key = base64_decode('the same key that used in login function');
try{
$decoded = JWT::decode($token, $key, array('HS256'));
return static::findByEmail($decoded->data->email);
}catch (\Exception $e){
return null;
}
}
The JWT library will raise an Exception if the token is no longer invalid (have been tampered or have been past the expiry time).
Then, add this to the behaviors function in every controller:
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
'except' => ['login'] //action that you don't want to authenticate such as login
];
That's it! I hope this work like you wanted. Oh, and there is lot of JWT libraries that you can use (you can see it here), but I personally use this library by people from firebase
You Can create Your Auth System, usually I do it.
You can Save Tokens for every user, and after it authentify user by that token.
In every action You can send that token for authentify user.
You need to do the following:
set the token before saving the user in the User model.
add actionLogin in the UserController to return the auth_key on user login.
in each API request you send the auth_key in the header instead of
sending username and password.
to check if the auth_key is valid, define 'authenticator' in the
UserController behaviors.
you can find code samples in my answer to another question here

Authentication with 2 different tables

I need to create a new "auth" config with another table and users. I have one table for the "admin" users and another table for the normal users.
But how can I create another instance of Auth with a different configuration?
While trying to solve this problem myself, I found a much simpler way. I basically created a custom ServiceProvider to replace the default Auth one, which serves as a factory class for Auth, and allows you to have multiple instances for multiple login types. I also stuck it all in a package which can be found here: https://github.com/ollieread/multiauth
It's pretty easy to use really, just replace the AuthServiceProvider in app/config/app.php with Ollieread\Multiauth\MultiauthServiceProvider, then change app/config/auth.php to look something like this:
return array(
'multi' => array(
'account' => array(
'driver' => 'eloquent',
'model' => 'Account'
),
'user' => array(
'driver' => 'database',
'table' => 'users'
)
),
'reminder' => array(
'email' => 'emails.auth.reminder',
'table' => 'password_reminders',
'expire' => 60,
),
);
Now you can just use Auth the same way as before, but with one slight difference:
Auth::account()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::user()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::account()->check();
Auth::user()->check();
It also allows you to be logged in as multiple user types simultaneously which was a requirement for a project I was working on. Hope it helps someone other than me.
UPDATE - 27/02/2014
For those of you that are just coming across this answer, I've just recently added support for reminders, which can be accessed in the same factory style way.
You can "emulate" a new Auth class.
Laravel Auth component is basically the Illuminate\Auth\Guard class, and this class have some dependencies.
So, basically you have to create a new Guard class and some facades...
<?php
use Illuminate\Auth\Guard as AuthGuard;
class CilentGuard extends AuthGuard
{
public function getName()
{
return 'login_' . md5('ClientAuth');
}
public function getRecallerName()
{
return 'remember_' . md5('ClientAuth');
}
}
... add a ServiceProvider to initialize this class, passing it's dependencies.
<?php
use Illuminate\Support\ServiceProvider;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Hashing\BcryptHasher;
use Illuminate\Auth\Reminders\PasswordBroker;
use Illuminate\Auth\Reminders\DatabaseReminderRepository;
use ClientGuard;
use ClientAuth;
class ClientServiceProvider extends ServiceProvider
{
public function register()
{
$this->registerAuth();
$this->registerReminders();
}
protected function registerAuth()
{
$this->registerClientCrypt();
$this->registerClientProvider();
$this->registerClientGuard();
}
protected function registerClientCrypt()
{
$this->app['client.auth.crypt'] = $this->app->share(function($app)
{
return new BcryptHasher;
});
}
protected function registerClientProvider()
{
$this->app['client.auth.provider'] = $this->app->share(function($app)
{
return new EloquentUserProvider(
$app['client.auth.crypt'],
'Client'
);
});
}
protected function registerClientGuard()
{
$this->app['client.auth'] = $this->app->share(function($app)
{
$guard = new Guard(
$app['client.auth.provider'],
$app['session.store']
);
$guard->setCookieJar($app['cookie']);
return $guard;
});
}
protected function registerReminders()
{
# DatabaseReminderRepository
$this->registerReminderDatabaseRepository();
# PasswordBroker
$this->app['client.reminder'] = $this->app->share(function($app)
{
return new PasswordBroker(
$app['client.reminder.repository'],
$app['client.auth.provider'],
$app['redirect'],
$app['mailer'],
'emails.client.reminder' // email template for the reminder
);
});
}
protected function registerReminderDatabaseRepository()
{
$this->app['client.reminder.repository'] = $this->app->share(function($app)
{
$connection = $app['db']->connection();
$table = 'client_reminders';
$key = $app['config']['app.key'];
return new DatabaseReminderRepository($connection, $table, $key);
});
}
public function provides()
{
return array(
'client.auth',
'client.auth.provider',
'client.auth.crypt',
'client.reminder.repository',
'client.reminder',
);
}
}
In this Service Provider, I put some example of how to create a 'new' password reminder component to.
Now you need to create two new facades, one for authentication and one for password reminders.
<?php
use Illuminate\Support\Facades\Facade;
class ClientAuth extends Facade
{
protected static function getFacadeAccessor()
{
return 'client.auth';
}
}
and...
<?php
use Illuminate\Support\Facades\Facade;
class ClientPassword extends Facade
{
protected static function getFacadeAccessor()
{
return 'client.reminder';
}
}
Of course, for password reminders, you need to create the table in database, in order to work. In this example, the table name should be client_reminders, as you can see in the registerReminderDatabaseRepository method in the Service Provider. The table structure is the same as the original reminders table.
After that, you can use your ClientAuth the same way you use the Auth class. And the same thing for ClientPassword with the Password class.
ClientAuth::gust();
ClientAuth::attempt(array('email' => $email, 'password' => $password));
ClientPassword::remind($credentials);
Don't forget to add your service provider to the service providers list in the app/config/app.php file.
UPDATE:
If you are using Laravel 4.1, the PasswordBroker doesn't need the Redirect class anymore.
return new PasswordBroker(
$app['client.reminder.repository'],
$app['client.auth.provider'],
$app['mailer'],
'emails.client.reminder' // email template for the reminder
);
UPDATE 2
Laravel 5.2 just introduced multi auth, so this is no longer needed in this version.
Ok, I had the same problem and here is how I solved it:
actually in laravel 4 you can simply change the auth configs at runtime so to do the trick you can simply do the following in your App::before filter:
if ($request->is('admin*'))
{
Config::set('auth.model', 'Admin');
}
this will make the Auth component to use th Admin model when in admin urls. but this will lead to a new problem, because the login session key is the same if you have two users in your admins and users table with the same id you will be able to login to the admin site if you have logged in before as a regular user! so to make the two different authetications completely independent I did this trick:
class AdminGuard extends Guard
{
public function getName()
{
return 'admin_login_'.md5(get_class($this));
}
public function getRecallerName()
{
return 'admin_remember_'.md5(get_class($this));
}
}
Auth::extend('eloquent.admin', function()
{
return new AdminGuard(new EloquentUserProvider(new BcryptHasher, 'Admin'), App::make('session.store'));
});
and change the App::before code to:
if ($request->is('admin*'))
{
Config::set('auth.driver', 'eloquent.admin');
Config::set('auth.model', 'Admin');
}
you can see that I made a new auth driver and rewrote some methods on the Guard class so it will generate different session keys for admin site. then I changed the driver for the admin site. good luck.
I had the same problem yesterday, and I ended up creating a much simpler solution.
My requirements where 2 different tables in two different databases. One table was for admins, the other was for normal users. Also, each table had its own way of hashing. I ended up with the following (Code also available as a gist on Github: https://gist.github.com/Xethron/6790029)
Create a new UserProvider. I called mine MultiUserProvider.php
<?php
// app/libraries/MultiUserProvider.php
use Illuminate\Auth\UserProviderInterface,
Illuminate\Auth\UserInterface,
Illuminate\Auth\GenericUser;
class MultiUserProvider implements UserProviderInterface {
protected $providers;
public function __construct() {
// This should be moved to the config later...
// This is a list of providers that can be used, including
// their user model, hasher class, and hasher options...
$this->providers = array(
'joomla' => array(
'model' => 'JoomlaUser',
'hasher' => 'JoomlaHasher',
)
'another' => array(
'model' => 'AnotherUser',
'hasher' => 'AnotherHasher',
'options' => array(
'username' => 'empolyee_number',
'salt' => 'salt',
)
),
);
}
/**
* Retrieve a user by their unique identifier.
*
* #param mixed $identifier
* #return \Illuminate\Auth\UserInterface|null
*/
public function retrieveById($identifier)
{
// Returns the current provider from the session.
// Should throw an error if there is none...
$provider = Session::get('user.provider');
$user = $this->createModel($this->providers[$provider]['model'])->newQuery()->find($identifier);
if ($user){
$user->provider = $provider;
}
return $user;
}
/**
* Retrieve a user by the given credentials.
*
* #param array $credentials
* #return \Illuminate\Auth\UserInterface|null
*/
public function retrieveByCredentials(array $credentials)
{
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
// Retrieve the provider from the $credentials array.
// Should throw an error if there is none...
$provider = $credentials['provider'];
$query = $this->createModel($this->providers[$provider]['model'])->newQuery();
foreach ($credentials as $key => $value)
{
if ( ! str_contains($key, 'password') && ! str_contains($key, 'provider'))
$query->where($key, $value);
}
$user = $query->first();
if ($user){
Session::put('user.provider', $provider);
$user->provider = $provider;
}
return $user;
}
/**
* Validate a user against the given credentials.
*
* #param \Illuminate\Auth\UserInterface $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(UserInterface $user, array $credentials)
{
$plain = $credentials['password'];
// Retrieve the provider from the $credentials array.
// Should throw an error if there is none...
$provider = $credentials['provider'];
$options = array();
if (isset($this->providers[$provider]['options'])){
foreach ($this->providers[$provider]['options'] as $key => $value) {
$options[$key] = $user->$value;
}
}
return $this->createModel($this->providers[$provider]['hasher'])
->check($plain, $user->getAuthPassword(), $options);
}
/**
* Create a new instance of a class.
*
* #param string $name Name of the class
* #return Class
*/
public function createModel($name)
{
$class = '\\'.ltrim($name, '\\');
return new $class;
}
}
Then, I told Laravel about my UserProvider by adding the following lines to the top of my app/start/global.php file.
// app/start/global.php
// Add the following few lines to your global.php file
Auth::extend('multi', function($app) {
$provider = new \MultiUserProvider();
return new \Illuminate\Auth\Guard($provider, $app['session']);
});
And then, I told Laravel to use my user provider instead of EloquentUserProvider in app/config/auth.php
'driver' => 'multi',
Now, when I authenticate, I do it like so:
Auth::attempt(array(
'email' => $email,
'password' => $password,
'provider'=>'joomla'
)
)
The class would then use the joomlaUser model, with the joomlaHasher, and no options for the hasher... If using 'another' provider, it will include options for the hasher.
This class was built for what I required but can easily be changed to suite your needs.
PS: Make sure the autoloader can find MultiUserProvider, else it won't work.
I'm using Laravel 5 native auth to handle multiple user tables...
It's not difficult, please check this Gist:
https://gist.github.com/danielcoimbra/64b779b4d9e522bc3373
UPDATE: For Laravel 5, if you need a more robust solution, try this package:
https://github.com/sboo/multiauth
Daniel