21

As the title suggests, is it possible to authenticate without DB (instead, using User Provider)?

I've seen posts about how to authenticate without password, but would it be ever possible to authenticate without DB?

Here is what I've been trying to achieve...

  1. Ask the user to submit a PIN
  2. Compare the PIN with a value within .env
  3. If the PIN is correct, authenticate the user

It seems to be possible to do authenticate without a traditional RDBMS by introducing a user provider.

However, the doc doesn't seem to describe how the user provider should look like.

Here are snippets of my code (well, I simply mimicked the doc)...

class AuthServiceProvider extends ServiceProvider { public function boot() { $this->registerPolicies(); Auth::provider('myUser', function ($app, array $config) { // Return an instance of Illuminate\Contracts\Auth\UserProvider... return new MyUserProvider($app->make('myUser')); }); } } 

In auth.php...

'providers' => [ 'users' => [ 'driver' => 'myUser', ], ], 

Now, I have no clue as to how to proceed.

So, I'd like to know...

  1. How the user provider should look like

  2. if it's possible to authenticate users with env() in the first place

Any advice will be appreciated.

4
  • I haven't looked into it too much, so can't really answer the question very well, but I think you'll want to look at authentication guards in Laravel. laravel.com/docs/5.6/authentication#adding-custom-guards Commented May 30, 2018 at 10:26
  • @PhilCross Thanks for your comment. Yeah I noticed it too, but doc doesn't explain how to achieve it really well :( Commented May 30, 2018 at 10:28
  • 1
    code.tutsplus.com/tutorials/… mattstauffer.com/blog/… medium.com/@sirajul.anik/… Hopefully these might help a little. I haven't read them, but they look alright. Commented May 30, 2018 at 10:30
  • I think you have to follow this path laravel-recipes.com/recipes/115/… Not sure exactly. I also do not have any experience in this kind of a situation. Since this is an interesting question I'm also trying to implement this as a learning project. Commented May 30, 2018 at 10:42

3 Answers 3

30

Create your own Guard ignoring UserProvider interface. I adopted it in my project and it's working well.

PinGuard.php

<?php declare(strict_types=1); namespace App\Auth\Guards; use App\User; use Illuminate\Auth\AuthenticationException; use Illuminate\Contracts\Auth\Authenticatable; use Illuminate\Contracts\Auth\Guard; use Illuminate\Http\Request; /** * Class PinGuard */ class PinGuard implements Guard { /** * @var null|Authenticatable|User */ protected $user; /** * @var Request */ protected $request; /** * OpenAPIGuard constructor. * * @param Request $request */ public function __construct(Request $request) { $this->request = $request; } /** * Check whether user is logged in. * * @return bool */ public function check(): bool { return (bool)$this->user(); } /** * Check whether user is not logged in. * * @return bool */ public function guest(): bool { return !$this->check(); } /** * Return user id or null. * * @return null|int */ public function id(): ?int { $user = $this->user(); return $user->id ?? null; } /** * Manually set user as logged in. * * @param null|\App\User|\Illuminate\Contracts\Auth\Authenticatable $user * @return $this */ public function setUser(?Authenticatable $user): self { $this->user = $user; return $this; } /** * @param array $credentials * @return bool */ public function validate(array $credentials = []): bool { throw new \BadMethodCallException('Unexpected method call'); } /** * Return user or throw AuthenticationException. * * @throws AuthenticationException * @return \App\User */ public function authenticate(): User { $user = $this->user(); if ($user instanceof User) { return $user; } throw new AuthenticationException(); } /** * Return cached user or newly authenticate user. * * @return null|\App\User|\Illuminate\Contracts\Auth\Authenticatable */ public function user(): ?User { return $this->user ?: $this->signInWithPin(); } /** * Sign in using requested PIN. * * @return null|User */ protected function signInWithPin(): ?User { // Implement your logic here // Return User on success, or return null on failure } /** * Logout user. */ public function logout(): void { if ($this->user) { $this->setUser(null); } } } 

NoRememberTokenAuthenticatable.php

User should mixin this trait.

<?php declare(strict_types=1); namespace App\Auth; use Illuminate\Database\Eloquent\Model; /** * Trait NoRememberTokenAuthenticatable * * @mixin Model */ trait NoRememberTokenAuthenticatable { /** * Get the name of the unique identifier for the user. * * @return string */ public function getAuthIdentifierName() { return 'id'; } /** * Get the unique identifier for the user. * * @return mixed */ public function getAuthIdentifier() { return $this->id; } /** * Get the password for the user. * * @return string * @codeCoverageIgnore */ public function getAuthPassword() { throw new \BadMethodCallException('Unexpected method call'); } /** * Get the token value for the "remember me" session. * * @return string * @codeCoverageIgnore */ public function getRememberToken() { throw new \BadMethodCallException('Unexpected method call'); } /** * Set the token value for the "remember me" session. * * @param string $value * @codeCoverageIgnore */ public function setRememberToken($value) { throw new \BadMethodCallException('Unexpected method call'); } /** * Get the column name for the "remember me" token. * * @return string * @codeCoverageIgnore */ public function getRememberTokenName() { throw new \BadMethodCallException('Unexpected method call'); } } 

AuthServiceProvider.php

<?php declare(strict_types=1); namespace App\Providers; use App\Auth\Guards\PinGuard; use Illuminate\Container\Container; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Auth; class AuthServiceProvider extends ServiceProvider { /** * The policy mappings for the application. * * @var array */ protected $policies = []; /** * Register any authentication / authorization services. */ public function boot() { Auth::extend('pin', function (Container $app) { return new PinGuard($app['request']); }); $this->registerPolicies(); } } 

config/auth.php

You should comment out most of them.

return [ /* |-------------------------------------------------------------------------- | Authentication Defaults |-------------------------------------------------------------------------- | | This option controls the default authentication "guard" and password | reset options for your application. You may change these defaults | as required, but they're a perfect start for most applications. | */ 'defaults' => [ 'guard' => 'web', // 'passwords' => 'users', ], /* |-------------------------------------------------------------------------- | Authentication Guards |-------------------------------------------------------------------------- | | Next, you may define every authentication guard for your application. | Of course, a great default configuration has been defined for you | here which uses session storage and the Eloquent user provider. | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | Supported: "session", "token" | */ 'guards' => [ 'web' => [ 'driver' => 'pin', ], // 'api' => [ // 'driver' => 'session', // 'provider' => 'users', // ], // 'web' => [ // 'driver' => 'session', // 'provider' => 'users', // ], ], /* |-------------------------------------------------------------------------- | User Providers |-------------------------------------------------------------------------- | | All authentication drivers have a user provider. This defines how the | users are actually retrieved out of your database or other storage | mechanisms used by this application to persist your user's data. | | If you have multiple user tables or models you may configure multiple | sources which represent each model / table. These sources may then | be assigned to any extra authentication guards you have defined. | | Supported: "database", "eloquent" | */ 'providers' => [ // 'users' => [ // 'driver' => 'eloquent', // 'model' => App\User::class, // ], // 'users' => [ // 'driver' => 'database', // 'table' => 'users', // ], ], /* |-------------------------------------------------------------------------- | Resetting Passwords |-------------------------------------------------------------------------- | | You may specify multiple password reset configurations if you have more | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. | | The expire time is the number of minutes that the reset token should be | considered valid. This security feature keeps tokens short-lived so | they have less time to be guessed. You may change this as needed. | */ // 'passwords' => [ // 'users' => [ // 'provider' => 'users', // 'table' => 'password_resets', // 'expire' => 60, // ], // ], ]; 
Sign up to request clarification or add additional context in comments.

7 Comments

Then you can normally use Auth Facade, like Auth::user() Auth::id()
should be the aceptes Answer
Using this solution, how would a normal login without db look like? Please help: stackoverflow.com/questions/60298133/…
And could you please show a code example of how to use this new guard. I am using this as a login request. But still not passing the auth middleware: $user = new User([ 'id' => $result->success->user->id, 'name' => $result->success->user->name, 'email' => $result->success->user->email, 'password' => $password ]); Auth::setUser($user); $re = Auth::authenticate();
|
26

Thank you all, but there was a much simpler solution... which is to use session().

In the controller,

public function login(Request $request) { if ($request->input('pin') === env('PIN')) { $request->session()->put('authenticated', time()); return redirect()->intended('success'); } return view('auth.login', [ 'message' => 'Provided PIN is invalid. ', ]); //Or, you can throw an exception here. } 

The route looks like,

Route::group(['middleware' => ['web', 'custom_auth']], function () { Route::get('/success', 'Controller@success')->name('success'); }); 

The custom_auth will looke like,

public function handle($request, Closure $next) { if (!empty(session('authenticated'))) { $request->session()->put('authenticated', time()); return $next($request); } return redirect('/login'); } 

Hope this will help someone.

3 Comments

what is the location of the custom_auth and did you create a simple <form> with just one input where users enter the PIN?
Please consider not using env() into your controller or model. You should create new config file in config/ directory. If you're using env(), you will get null value after caching your config. Docs
Every user has the same pin? Or there is only one User? BC there will only be one pin to the env variable set to PIN. Am I missing something? There's no way that this works....
-5

If you know who the user is (IE: have a $user instance already), you can simply login without using any guards as shown in the documentation

Auth::login($user); 

I would pass in a User instance instead of $email/$password to your function

$user = User::whereEmail($email)->first(); $class->login($user); 

and then in your class

public static function Login(User $user) { // ... if(substr ( $result, 0, 3 ) == '+OK') Auth::login($user); return true; //user will be logged in and then redirect else return false; } 

3 Comments

Thank your for your suggestion... but I'm in a situation where DB is not available. So, User::whereEmail won't get any instance. Also, I don't think that Auth::login($user) can be used, since I don't have any user instance.
Maybe this answer is not the best for the question, but google brought me here and its what I was looking for :)
Answers provide bits and pieces of information. Would be great if there was a working sample .. Are there any available?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.