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
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 );
}
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 ?
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
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
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);
}