Laravel 5.2 Custom Auth fail after next request - php

I write a custom user provider to validate my user in a external API on external server.
CustomUserProvider:
<?php
namespace App\Auth;
use Illuminate\Auth\GenericUser;
use Illuminate\Contracts\Auth\Authenticatable as Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Psr\Http\Message\ResponseInterface;
use Illuminate\Http\Request;
use App\XXX\Facades\XXXX;
use Log;
class CustomUserProvider implements UserProvider {
public $errors = [];
public function getErrorMessages ( ) {
return $this->errors;
}
public function retrieveById($identifier)
{
// TODO: Implement retrieveById() method.
}
public function retrieveByToken($identifier, $token)
{
// TODO: Implement retrieveByToken() method.
return null;
}
public function updateRememberToken(Authenticatable $user, $token)
{
// TODO: Implement updateRememberToken() method.
}
public function retrieveByCredentials(array $credentials)
{
$response =APIService::get( 'GET', $credentials, 'tokens');
if ( array_key_exists('code', $response) ) {
/* Exception o Credentials Error */
$this->errors = $response;
return null;
} else {
$apiCredentials = json_decode( $response->getBody(), true );
if( $apiCredentials ) {
$attributes = array (
'id' => 1,
'name' => 'Name',
'lastname' => 'LastName',
'email' => 'email#email.com'
);
$user = new GenericUser( $attributes );
return $user;
}
}
return null;
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
if( $user->email == $credentials['email'] ) {
return true;
}
return false;
}
}
The problem is that the user if logged fine, but in the next request Auth::user() returns false. Debugging in the middleware Auth:user() is returning false too.

Related

how can i get auth user or any session in the my custom class and provider?

i have to get the company which user chooses but i can't get user data in my class and provider boot function .
user can have more than one company so user have to choose a company for some operations. But as i said , i can't get the company which user chooses.
Like this :
public function boot()
{
$user = Auth::user();
dd( $user ); // return null;
$bid = new Bid();
$show = $bid->check();
Blade::directive('bid',function() use($show){
return "<?php if( $show ) { ?>";
});
Blade::directive('endbid',function(){
return '<?php } ?>';
});
}
My other class :
<?php
namespace App\Services\Buying\Package;
use App\Services\Buying\Package\PackageInterface;
use App\Models\Company\Company;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use App\User;
class PackageBuying extends PackageQuery implements PackageInterface
{
private $company_id;
public function __construct()
{
$user = Auth::user();
dd( $user ); // return null
$this->setCompanyId($this->company_id);
}
public function setSession( Request $request )
{
$request->session()->get('selected-company');
}
public function company()
{
return $this->company_id;
}
public function package()
{
if ( $this->check() ) {
return $this->getPackage($this->company())->first();
}
return [];
}
public function features()
{
return (object)json_decode( $this->package()->features );
}
public function importantFeatures()
{
return (object)json_decode( $this->package()->important_features );
}
public function active()
{
return (bool) $this->getPackage()->firstOrFail()->active;
}
}
Actually if i got user data in the provider boot function , i could send data to my class .
May you please help me ?
Thanks in advance.
Put the code inside your construct function to calMethod function like this
public function callAction( $method, $parameters ) {
$user = Auth::user();
dd( $user ); // return null
$this->setCompanyId($this->company_id);
return parent::callAction( $method, $parameters );
}

Reset password in laravel nova

I'm trying to combine Laravel project and Nova admin panel. In the project I need to reset Nova password, But there is a FatalThrowableError error in PasswordBroker.php file.
This is the error
This is my PasswordBroker.php file.
<?php
namespace Illuminate\Auth\Passwords;
use Closure;
use Illuminate\Support\Arr;
use UnexpectedValueException;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class PasswordBroker implements PasswordBrokerContract
{
protected $tokens;
protected $users;
protected $passwordValidator;
public function __construct(TokenRepositoryInterface $tokens,
UserProvider $users)
{
$this->users = $users;
$this->tokens = $tokens;
}
public function sendResetLink(array $credentials)
{
$user = $this->getUser($credentials);
if (is_null($user)) {
return static::INVALID_USER;
}
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
return static::RESET_LINK_SENT;
}
public function reset(array $credentials, Closure $callback)
{
$user = $this->validateReset($credentials);
if (! $user instanceof CanResetPasswordContract) {
return $user;
}
$password = $credentials['password'];
$callback($user, $password);
$this->tokens->delete($user);
return static::PASSWORD_RESET;
}
protected function validateReset(array $credentials)
{
if (is_null($user = $this->getUser($credentials))) {
return static::INVALID_USER;
}
if (! $this->validateNewPassword($credentials)) {
return static::INVALID_PASSWORD;
}
if (! $this->tokens->exists($user, $credentials['token'])) {
return static::INVALID_TOKEN;
}
return $user;
}
public function validator(Closure $callback)
{
$this->passwordValidator = $callback;
}
public function validateNewPassword(array $credentials)
{
if (isset($this->passwordValidator)) {
list($password, $confirm) = [
$credentials['password'],
$credentials['password_confirmation'],
];
return call_user_func(
$this->passwordValidator, $credentials
) && $password === $confirm;
}
return $this->validatePasswordWithDefaults($credentials);
}
protected function validatePasswordWithDefaults(array $credentials)
{
list($password, $confirm) = [
$credentials['password'],
$credentials['password_confirmation'],
];
return $password === $confirm && mb_strlen($password) >= 6;
}
public function getUser(array $credentials)
{
$credentials = Arr::except($credentials, ['token']);
$user = $this->users->retrieveByCredentials($credentials);
if ($user && ! $user instanceof CanResetPasswordContract) {
throw new UnexpectedValueException('User must implement CanResetPassword interface.');
}
return $user;
}
public function createToken(CanResetPasswordContract $user)
{
return $this->tokens->create($user);
}
public function deleteToken(CanResetPasswordContract $user)
{
$this->tokens->delete($user);
}
public function tokenExists(CanResetPasswordContract $user, $token)
{
return $this->tokens->exists($user, $token);
}
public function getRepository()
{
return $this->tokens;
}
}
Here I want to reset current password using email. Does anyone have a idea to fix this issue ?

Error while getting authenticated user in Laravel using JWT

I was able to login and get user token using JWT in laravel.However, while tring to get authenticated user (getAuthUser) by passing that token, I get following error:
"SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'where
clause' (SQL: select * from user where `` = 12 limit 1)"
AuthenticationController:
<?php
namespace Modules\Authentication\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests;
use JWTAuth;
use JWTAuthException;
use Modules\Settings\Entities\Users;
use Modules\Authentication\Http\Requests\Authentication;
class AuthenticationController extends Controller
{
public function __construct()
{
// $this->user = new Users;
$this->guard = \Auth::guard('api');
}
public function login(Authentication $request){
$credentials = $request->only('username', 'password');
try {
// verify the credentials and create a token for the user
$token = JWTAuth::attempt($credentials);
if (! $token = JWTAuth::attempt($credentials)) {
return response()->json(['error' => 'invalid_credentials'], 401);
}
} catch (JWTException $e) {
// something went wrong
return response()->json(['error' => 'could_not_create_token'], 500);
}
// if no errors are encountered we can return a JWT
return response()->json(compact('token'));
}
public function getAuthUser(Request $request){
$user = JWTAuth::user($request->token);
// dd($user);
return response()->json(['result' => $user]);
}
}
Users Model:
namespace Modules\Settings\Entities;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class Users extends Model implements JWTSubject,Authenticatable{
Protected $table="user";
// protected $primaryKey = 'id';
protected $fillable = ['id','username','password','user_status_type_id','client_id','created_userid'];
protected $hidden = [
'password', 'remember_token',
];
public function user_status(){
return $this->belongsTo('Modules\Settings\Entities\UserStatusType','user_status_type_id');
}
public function user_client(){
return $this->belongsTo('Modules\Settings\Entities\Client','client_id');
}
public function role()
{
return $this->belongsToMany('Modules\Settings\Entities\Role','user_role','user_id','role_type_id');
}
public function getAuthPassword() {
return $this->password;
}
public function getJWTIdentifier() {
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
public function getAuthIdentifierName(){}
public function getAuthIdentifier(){}
// public function getAuthPassword(){}
public function getRememberToken(){}
public function setRememberToken($value){}
public function getRememberTokenName(){}
}
Route:
Route::group(['middleware' => 'web', 'prefix' => 'api/v1/authentication', 'namespace' => 'Modules\Authentication\Http\Controllers'], function(){
Route::post('auth/login', 'AuthenticationController#login');
// Route::group(['middleware' => 'jwt.auth'], function () {
Route::get('user', 'AuthenticationController#getAuthUser');
// });
});
I am testing it in postman by
GET: ..../api/v1/authentication/user?token={Token}
EDIT:
Now my method for getAuthUser in the controller looks like this:
public function getAuthUser(Request $request){
// $token = JWTAuth::getToken();
// dd($token);
$input = $request->all();
JWTAuth::setToken($input['token']);
// dd($input['token']);
$user = JWTAuth::toUser($input['token']);
// dd($user);
return response()->json(['result' => $user]);
}
and In JWTAuth.php
public function authenticate()
{
// dd($this->getPayload()->get('sub'));
$id = $this->getPayload()->get('sub');
// dd($id);
// dd($this->auth->byId($id));
if (! $this->auth->byId($id)) {
return false;
}
return $this->user();
}
here by doing dd($id), value of id comes but if I try to do dd($this->auth->byId($id)) I get the same error as before.
Try this to retrieve the user instead:
public function getAuthUser()
{
try {
if (! $user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
return response()->json(['token_invalid'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['token_absent'], $e->getStatusCode());
}
// the token is valid and we have found the user via the sub claim
return response()->json(['result' => $user]);
}
Taken from docs, Retreiving the Authenticated user from a token
EDIT:
May not make a difference but just looking at your Model again and I would say that it needs to be
class Users extends Authenticatable implements JWTSubject
rather than
class Users extends Model implements JWTSubject,Authenticatable

Laravel middleware throws error that depedency needs to implement contract, while it does

Type error: Argument 3 passed to App\Http\Middleware\UserAuthMiddleware::handle() must implement interface App\Contracts\UserAuth, none given, called in C:\wamp64\www\laravel\vendor\laravel\framework\src\Illuminate\Pipeline\Pipeline.php on line 148
I'm getting this error from inside a middleware, but when I'm use the given contract in my controllers, it works just fine. Does anyone have a clue what is happening?
Middleware file
namespace App\Http\Middleware;
use Closure;
use App\Contracts\UserAuth;
class UserAuthMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, UserAuth $user)
{
return $next($request);
}
}
UserAuth service file
<?php
namespace App\Services;
use App\UsersModel;
class UserAuth implements \App\Contracts\UserAuth
{
public $username;
public $password;
public $perm_level = "admin";
public $guest = true;
public function load()
{
if (session()->has("user"))
{
$user = UserModel::where([
"username" => session("user"),
"password" => session("password")
])->first();
$this->username = $user->username;
$this->password = $user->password;
$this->guest = false;
}
}
public function isLogged()
{
return $this->guest;
}
}
AppServiceProvider register
public function register()
{
$this->app->singleton(\App\Contracts\UserAuth::class, \App\Services\UserAuth::class);
}
Routes
//REGISTRATION ROUTES
Route::get("/register", "User#register")->middleware("user_auth");
Route::post("/register", "User#save_user")->middleware("user_auth");
User controller with working contract
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\UsersModel;
use App\Contracts\UserAuth;
class User extends Controller
{
public function register(Request $request, UserAuth $user)
{
return view("registration.form", ["request" => $request]);
}
public function login(Request $request)
{
$user = UsersModel::where([
"username" => $request->username,
"password" => $request->password
])->first();
if ($user)
{
session(["user" => $user->username, "password" => $user->password]);
return back();
}
else return back()->with("login_attempt", "failed");
}
public function logout()
{
session()->forget("user", "password");
return back();
}
public function save_user(Request $request)
{
$errors = [];
//Data validation
$input = $request->all();
if ( in_array(null, $input) )
$errors["empty_fields"] = true;
if ( !preg_match("/[A-Za-z0-9 ]{3,16}/", $input["username"]) )
$errors["invalid_username"] = true;
if ( $input["password"] != $input["password_confirm"] )
$errors["unmatching_passwords"] = true;
if ( !preg_match("/[A-Za-z0-9\-\.]{3,16}#[A-Za-z0-9](\.[a-z0-9]){1,2}/", $input["email"]) )
$errors["invalid_email"] = true;
if ( UsersModel::where("username", $input["username"])->first() )
$errors["username_taken"] = true;
if (count($errors) > 0) return view("registration.form", ["err" => $errors, "request" => $request]);
else return view("registration.save", ["request" => $request]);
}
}
You are incorrectly trying to pass an ad-hoc paramter to the handle function in your middleware parameter.
When you define this:
public function handle($request, Closure $next, UserAuth $user)
That means that the middleware is expecting a parameter to be passed in there, it will not come from DI Container, hence the $user variable is null, failing to pass the type-hint constraint.
The parameters that are allowed here are only for "roles", you cannot pass something random and expect the DI container to resolve it.
I would suggest you try something like this instead:
public function handle($request, Closure $next)
{
if($request->user()->isLogged()) {
return $next($request);
} else {
return redirect('login'); // or whatever route
}
}
For this to work, you would need to define the isLogged function as part of a Trait, that you would add to you App\User model.
Please see:
https://laracasts.com/discuss/channels/laravel/pass-variable-from-route-to-middleware
https://laravel.com/docs/5.4/middleware#middleware-parameters

Silex framework : Create an UserProvider/PasswordEncoder/User

I use the framework Silex, especially SecurityServiceProvider.
I have to create my own User class (because my salt is the username => with the default class the salt is null) :
<?php
namespace Adh\Security;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
class User implements AdvancedUserInterface {
private $username;
private $password;
public function __construct($username, $password)
{
$this->username = $username;
$this->password = $password;
}
public function getRoles()
{
return array();
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->username;
}
...
}
Until this, no problem. Now, I have to create a custom UserProvider to retrieve my user from MySQL :
<?php
namespace Adh\Security;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\User;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Doctrine\DBAL\Connection;
class UserProvider implements UserProviderInterface
{
private $conn;
public function __construct(Connection $conn)
{
$this->conn = $conn;
}
public function loadUserByUsername($username)
{
$stmt = $this->conn->executeQuery('SELECT * FROM account WHERE username like ?', array($username));
if (!$user = $stmt->fetch()) {
throw new UsernameNotFoundException(sprintf('Le nom d\'utilisateur "%s" n\'existe pas', $username));
}
return new \Adh\Security\User($user['username'], $user['sha_pass_hash']);
}
...
}
And to register the security provider :
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'user' => array(
'pattern' => '^/user',
'form' => array('login_path' => '/connexion', 'check_path' => '/user'),
'users' => $app->share(function () use ($app) {
return new Adh\Security\UserProvider($app['db']);
})
)
)
));
$app['security.encoder_factory'] = $app->share(function ($app) {
return new EncoderFactory(
array('Adh\Security\User' => new Adh\Security\PasswordEncoder())
);
});
It works, except when the authentification is positive (the username and password match) I've this exception :
RuntimeException: There is no user provider for user
"Adh\Security\User".
How to set my UserProvider for my User class ?
Thank's
I found the solution. To create my provider I followed this example : http://silex.sensiolabs.org/doc/providers/security.html#defining-a-custom-user-provider
In the refreshUser method:
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
This is correct for the default User class: I have my own User class so the exception is raised.
The condition becomes :
if (!$user instanceof \Adh\Security\User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
Your function
loadUserByUsername()
does not return any role. By default a Symfony\Component\Security\Core\User\User record is returned with the roles of the user as third parameter. At least any user must have one role.
Sample:
use Symfony\Component\Security\Core\User\User;
public function loadUserByUsername($username)
{
$frameworkUser = new FrameworkUser($this->app);
if (false === ($user = $frameworkUser->selectUser($username))) {
throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
}
return new User($user['username'], $user['password'], $user['roles'], true, true, true, true);
}

Categories