set custom sql for Authorization in Laravel 5 - php

I am new on Laravel and use Authorization. I am looking for the way to change default sql for Auth. Actually, Laravel does it using this simple sql command at below:
SELECT * FROM users WHERE login="something" AND password = "something" LIMIT 1
I am trying to change default sql like this:
SELECT
u.id, u.name, c.company
FROM
users u, companies c
WHERE
u.login="something" AND
u.password = "something" AND
u.companyId = c.id
LIMIT 1
I understood that I should create custom Authorization system: crate new user Provider and Auth Provider.
Firstly, I created Auth folder inside App and added there CustomUserProvider.php
CustomUserProvider.php
<?php namespace App\Auth;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Contracts\Auth\UserProvider as UserProviderInterface;
use App\Models\User;
class CustomUserProvider implements UserProviderInterface {
protected $model;
public function __construct(UserContract $model)
{
$this->model = $model;
}
public function retrieveById($identifier)
{
}
public function retrieveByToken($identifier, $token)
{
}
public function updateRememberToken(UserContract $user, $token)
{
}
public function retrieveByCredentials(array $credentials)
{
}
public function validateCredentials(UserContract $user, array $credentials)
{
}
}
My customAuthProvider.php file, in App/Providers:
<?php namespace App\Providers;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\Auth\CustomUserProvider;
use Illuminate\Support\ServiceProvider;
class CustomAuthProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
$this->app['auth']->extend('custom',function()
{
return new CustomUserProvider(new User);
});
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
At the end I set driver to custom in config/Auth.php
'driver' => 'custom'
I am looking for the way using this custom classes how can I use custom sql command for Authorization (Login)?
Or maybe this way is wrong?

If all you need are additional constraints on the query that fetches user from the database during authentication, there is much simpler way to do that.
First of all, Laravel offers an AuthenticatesUsers trait that you can use in your controller to handle authentication requests. The default implementation fetches user from the database using username field and then, if matching user is found, it validates their password.
The list of attributes that is used to fetch user from the database can be customized by overriding getCredentials method in your controller. In your case the following should be enough to load user using their username and company id:
protected function getCredentials(Request $request)
{
return $request->only($this->loginUsername(), 'password', 'companyId);
}
Once you add that, user should provide their username, companyId and password in the login form and they will be authenticated only if there exists a user with given username that belongs to given company and the password provided is valid.
UPDATE: If you decide not to use the trait, but want to authenticate users manually, you can do so in a really similar manner. When calling Auth::attempt() you just need to pass all the criteria that should be used to authenticate the user, e.g.:
Auth::attempt([
'username' => Input::get('username'),
'companyId' => Input::get('companyId'),
'password' => Input::get('password')
]);

I tried this package and it helped me:
https://github.com/ollieread/multiauth/

Related

Using custom authentication on Laravel 6

I would like to manually authenticate the users in my company. The issue is that, I have 2 tables, called Student and Staff in the Oracle database.
As for the Student table, I get the idea of overriding the built in Auth method provided through the auth scaffolding command as the username and password are stored right into the table.
As for the Staff table, the password is stored a different column/table and encrypted using a stored procedure/package so the only way to get the user validation is by calling the package which only returns 0 or 1 only.
What I have done,
I wrote my own Routes, and added my own functions in LoginController.
public function loginStaff(Request $req){
$username = Str::upper($req->input('username'));
$password = $req->input('password');
$users = PortalUser::where('ID', $username)->firstOrFail();
if ($users->user_type == 'STAFF'){
$queryResult = DB::select('select PACKAGE.validStaff(?,?) from dual',[$username, $password]);
if($queryResult == 1){
//this is where I would like to auth the user.
//using Auth::Attempt and Auth::Login will only run the default query
}
}
I have successfully returned value of 1 and 0 in the controller.
So is there anything that I am missing?
Or should I manually set the session by myself using the session() method?
Thank you.
If you want to manually authenticate users, you can easily use sessions. Have the following code as reference:
//this is where I would like to auth the user.
//using Auth::Attempt and Auth::Login will only run the default query
// typically you store it using the user ID, but you can modify the session using other values.
session()->put('user_id', user id from database here);
And if you want to check whether user is authenticated, modify RedirectIfAuthenticated middleware to this:
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (session()->has('user_id')) {
return redirect( custom path here );
}
return $next($request);
}
}
When you want to logout the user, simply destroy the session key
session()->forget('user_id');
**Note: ** many broadcasting and addons use Laravel's authentication system (Guards) and you may need to hook into their code if you want to use them with your custom auth system
Laravel provides Custom Session Drivers which you can use to create or delete your sessions
<?php
namespace App\Extensions;
class MongoSessionHandler implements \SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
Hope it helps, if not then comment down below. Will help you out.
###### Update #######
I think then you do have to make custom HTTP sessions from Laravel
Step 1: Create another table in your database for session, like this;
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->unsignedInteger('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
Step 2: Store data in the session, you will typically use the put method or the session helper;
// Via a request instance...
$request->session()->put('key', 'value');
// Via the global helper...
session(['key' => 'value']);
Step 3: Get the key for specific user when your function returns 1
$value = $request->session()->get('key', function () {
return 'default';
});
Step 4: Delete the session, after some time you need to delete the session for security reasons then you can do.
$value = $request->session()->pull('key', 'default');

Custom Recaller Laravel

I want change default cookie remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d to myprefix_web_59ba36addc2b2f9401580f014c7f58ea4e30989d
I find code in Illuminate\Auth\SessionGuard
/**
* Get the name of the cookie used to store the "recaller".
*
* #return string
*/
public function getRecallerName() {
return 'remember_'.$this->name.'_'.sha1(static::class);
}
How i can create custom SessionGuard? Somebody can help me?
Since the built in SessionGuard does not have a way to change this, you will need to create your own Guard class to override the method, and tell Auth to use your Guard class. This information is also explained in my answer here, which explains how to customize the TokenGuard.
First, start by creating a new Guard class that extends the base SessionGuard class. In your new Guard class, you will override the getRecallerName() method to return the name you want. In this example, it is created at app/Services/Auth/MySessionGuard.php:
namespace App\Services\Auth;
use Illuminate\Auth\SessionGuard;
class MySessionGuard extends SessionGuard
{
/**
* Get the name of the cookie used to store the "recaller".
*
* #return string
*/
public function getRecallerName()
{
return 'myprefix_'.$this->name.'_'.sha1(static::class);
}
}
Once you've created your class, you need to let Auth know about it. You can do this in the boot() method on your AuthServiceProvider service provider:
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
Auth::extend('mysession', function($app, $name, array $config) {
$provider = $this->createUserProvider($config['provider']);
$guard = new \App\Services\Auth\MySessionGuard($name, $provider, $app['session.store']);
// When using the remember me functionality of the authentication services we
// will need to be set the encryption instance of the guard, which allows
// secure, encrypted cookie values to get generated for those cookies.
if (method_exists($guard, 'setCookieJar')) {
$guard->setCookieJar($app['cookie']);
}
if (method_exists($guard, 'setDispatcher')) {
$guard->setDispatcher($app['events']);
}
if (method_exists($guard, 'setRequest')) {
$guard->setRequest($app->refresh('request', $guard, 'setRequest'));
}
return $guard;
});
}
And finally, you need to tell Auth to use your new mysession guard. This is done in the config/auth.php config file.
'guards' => [
'web' => [
'driver' => 'mysession',
'provider' => 'users',
],
],

laravel5.1 Manually Authenticating Users

In my app I use the default authentification to login my users to their dashboard.
Now I would like to create a backend for supporters and one for admins.
I use this code at the moment to login as admin:
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App;
use Artisan;
use Validator;
use Auth;
class AdminLoginController extends Controller
{
public function index()
{
return view('admin.login');
}
public function authenticate(Request $request)
{
if (Auth::attempt(['username' => $request->username, 'password' => $request->password, 'id' => 1]))
{
// Authentication passed...
dd("correct");
}
else
{
dd("login data incorrect!");
}
}
}
How can I use now the well known redirects after login.
In my AuthController I use for the users I use this code:
/**
* Where to redirect users after login / registration.
*
* #var string
*/
protected $redirectTo = '/dashboard';
protected $redirectAfterLogout = 'auth/login';
protected $redirectPath = '/dashboard';
1.) How can I use this in my code above? I would like to redirect admins logged into the app like users to specified urls using this laravel feature.
2.) What's the best way, to check more "ids" in the if statement? Because there will be more than one admin.
first of all you are checking username, password along with a ID. So only user with Id = 1 is going to be authenticated by your function. You dont need to put an id check there.
Now for the redirect you can make a function which returns back the url based on the user type. Here is a very basic example`
public function getRedirectUrl(){
if(auth()->user()->isAdmin()){
return url('/admin-dashboard');
}
elseif(auth()->user()->isUser()){
return url('/user-dashboard')
}
}
Make sure you have isAdmin() and isUser() function defined in your User model like
public function isAdmin(){
return $this->user_type == UserType::ADMIN;
}
So in your authentication function just do return redirect($this->getRedirectUrl())

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');

Laravel 4 - Hardcoded authentication

I want to create authentication mechanism without need for database where only one person (admin) who knows right username and password (which I would hardcode) would be able to login. I still want to use Auth::attempt(), Auth::check() and other functions.
I found out that I could create my own User driver, but it seems to me that there should be something simpler.
Maybe it is not very nice solution, but I want as simple as possible website.
It may only seem there should be something simpler, but in fact that's as simple as you can get if you want to extend the authentication system. All the methods you're using through the Auth facade (like attempt, check, etc.), are implemented within the Illuminate\Auth\Guard class. This class needs a UserProviderInterface implementation to be injected into the constructor in order to work. Which means that in order to use the Auth facade you either need to use the already implemented DatabaseUserProvider or EloquentUserProvider, or implement your own provider that handles the simple login you want.
Although the article you linked to may look lengthy, to achieve what you need you might get away with much less code in the provider than you might think. Here's what I think is what you need:
1. In your app/config/auth.php change the driver to simple and append the desired login credentials:
'driver' => 'simple',
'credentials' => array(
'email' => 'user#email.com',
'password' => 'yourpassword'
)
2. Create a file in your app directory called SimpleUserProvider.php that has this code:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserProviderInterface;
class SimpleUserProvider implements UserProviderInterface {
protected $user;
public function __construct(array $credentials)
{
$this->user = new GenericUser(array_merge($credentials, array('id' => null)));
}
// If you only need to login via credentials the following 3 methods
// don't need to be implemented, they just need to be defined
public function retrieveById($identifier) { }
public function retrieveByToken($identifier, $token) { }
public function updateRememberToken(UserInterface $user, $token) { }
public function retrieveByCredentials(array $credentials)
{
return $this->user;
}
public function validateCredentials(UserInterface $user, array $credentials)
{
return $credentials['email'] == $user->email && $credentials['password'] == $user->password;
}
}
3. Lastly you'll need to register the new provider with the authentication system. You can append this to the app/start/global.php file:
Auth::extend('simple', function($app)
{
return new SimpleUserProvider($app['config']['auth.credentials']);
});
This should give you a simple (no database) user authentication while still being able to use Laravel's facades.
The accepted answer did not work for me. Every time I logged in, the login was successful but when on the /home page, I was redirected to the login page again.
I found out that this was due to the user not being stored in the session as authenticated user. To fix this, I had to implement the getAuthIdentifier method in the User model class and also implement the retrieveById method .
I've also adjusted my solution to support multiple hard coded users (it presumes, that the email is unique, so we can also use it as id for the user):
1. In app/config/auth.php:
'providers' => [
'users' => [
'driver' => 'array',
],
],
'credentials' => [
'userA#email.com' => 'passA',
'userB#email.com' => 'passB',
]
2. The UserProvider:
use \Illuminate\Auth\GenericUser;
use \Illuminate\Contracts\Auth\UserProvider;
use \Illuminate\Contracts\Auth\Authenticatable;
class ArrayUserProvider implements UserProvider
{
private $credential_store;
public function __construct(array $credentials_array)
{
$this->credential_store = $credentials_array;
}
// IMPORTANT: Also implement this method!
public function retrieveById($identifier) {
$username = $identifier;
$password = $this->credential_store[$username];
return new User([
'email' => $username,
'password' => $password,
]);
}
public function retrieveByToken($identifier, $token) { }
public function updateRememberToken(Authenticatable $user, $token) { }
public function retrieveByCredentials(array $credentials)
{
$username = $credentials['email'];
// Check if user even exists
if (!isset($this->credential_store[$username])) {
return null;
}
$password = $this->credential_store[$username];
return new GenericUser([
'email' => $username,
'password' => $password,
'id' => null,
]);
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
return $credentials['email'] == $user->email && $credentials['password'] == $user->getAuthPassword();
}
}
3. And in app/Providers/AuthServiceProvider:
use Illuminate\Support\Facades\Auth;
class AuthServiceProvider extends ServiceProvider
{
...
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
Auth::provider('array', function($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new ArrayUserProvider($app['config']['auth.credentials']);
});
}
}
4. In User.php (model):
class User extends Authenticatable
{
...
public function getAuthIdentifier()
{
return $this->email;
}
}
More Information:
For everyone who is interested, why there need to be the above stated additions:
When you login, the method login in Illuminate\Auth\SessionGuard is called. In this method you will find, that the identifier of the user is stored in the session with $this->updateSession($user->getAuthIdentifier()). Therefore we need to implement this method in our user model.
When you add $this->middleware('auth') in your controller, then the method authenticate() in Illuminate\Auth\Middleware\Authenticate is called. This again calls $this->auth->guard($guard)->check() to check, whether a user is authenticated. The check() method only tests, that there exists a user in the session (see Illuminate\Auth\GuardHelpers). It does this by calling the user() method of the guard, which in this case is again SessionGuard. In the user() method, the user is retrieved by taking the id stored in the session and calling retrieveById to get the user.

Categories