I am new to Laravel and I am using tutorial for web app. Tutorial uses Laravel 4 whereas I am using Laravel 5. I solved register issue but when I set down to test for login following errors shown up:
ErrorException in EloquentUserProvider.php line 111: Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\user given, called in C:\Users\Pujan\Desktop\projectlaravel\vendor\laravel\framework\src\Illuminate\Auth\Guard.php on line 390 and defined.
I'm not able to figure out the issue here. What actually means credentials. I know Laravel 5 has inbuilt login features but couldn't use it so I tried out different ways but this problem out of my focus.
My usercontroller is:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use View;
use App\user;
use Input;
use App\Http\Requests\YourFormRequest;
use Auth;
//use Illuminate\Support\Facades\Auth;
class UserController extends Controller
{
public $restful = true;
public function index()
{
return View::make('users.new')->with('title', 'Make it snappy Q&A - Register');
}
public function create(YourFormRequest $request)
{
User::create($request->all());
return redirect('/')->with('message','Thanks for registering!');
}
public function getlogin()
{
// return \Auth::user();
return View::make('users.login')->with('title','Make it snappy Q&A - Login ');
}
public function createlogin()
{
$user = array(
'username'=>Input::get('username'),
'password'=>Input::get('password')
);
if (Auth::attempt($user))
{
return redirect('/')->with('message','You are logged in:');
}else{
return redirect('login')
->with('message','Your username or password are incorrect pls chk it out')
->with_input();
}
}
I have my routes:
Route::get('/','Questions#index');
Route::get('register','UserController#index');
Route::get('login','UserController#getlogin');
Route::post('register','UserController#create');
Route::post('login','UserController#createlogin');
My login layout is working properly but as I try to login above errors show up. I think this error belongs to inbuilt Laravel 5 features but I am not able to match the setting inbuilt and my created login functionality.
The error you're seeing isn't related to your login code. Your User entity should implement the Illuminate\Contracts\Auth\Authenticatable interface. An interface is a contract, it lists methods/functions that a class must have. The class definition should look like this:
class User extends Model implements Authenticatable
{
On a quick glance of your code, there are other things you can do to clean it up:
public function createlogin()
{
if (Auth::attempt(Input::only('username', 'password'))) {
return redirect('/')->with('message','You are logged in:');
}
return redirect('login')
->with('message','Your username or password are incorrect pls chk it out')
->with_input();
}
And on a final note, I'd stop using the tutorial you're following. Laravel's latest documentation has a quick start guide that covers authentication, there are two versions, beginnner and intermediate.
What #Logan has suggested is true, and you should follow that.
I'll just go with cleaning of your code a bit.
Whenever you are dealing with validations, you should treat it as a separate stuff and for that you need to create the FormRequest object.
Refer this document on how to create the form request.
Then update the authorize and rules method with the following:
/**
* Authorize the request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'username' => 'required|exists:users|alpha_dash|min:4',
'password' => 'required'
];
}
Now in your createLogin method
/**
* Log in the user.
*
* #param \App\Http\Requests\YourFileRequest $request
* #return \Illuminate\Http\RedirectResponse
*/
public function createlogin(YourFileRequest $request)
{
$credentials = $request->only('username', 'password');
if (Auth::attempt($credentials)) {
return redirect('/')->with('message','You are logged in:');
}
return redirect('login')
->with('message', 'Invalid credentials')
->with_input();
}
Now you see how your code is simple and readable when you visit after 6 months from now ? It has to be like that. Validation logic in separate file and your Login logic in the controller. According to me, this helps a lot when you are testing via phpUnit, phpSpec or any other testing tool you are using.
Me and Logan have also replaced your if statement block. That is because, you should avoid the else block as far as possible when you are returning something from both if and else block.
Just a side note:
You should always try to follow 3 principles while programming / coding: SOLID, KISS, and DRY.
Kindly document your code whenever you are done with that part of the code. This is will again help future programmers and also for future reference to know what that piece of code is doing.
Hope this helps you out. Cheers.
Not sure whether you have solved this issue or not but I'm putting my experience here, maybe it could help someone else looking for a solution to this problem which happened exactly with me.
Your App/User model class should extends Illuminate\Foundation\Auth\User and not the Eloquent Model.
So change your User model to this:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
Instead of
class User extends Model
It did resolve this same error for me. Hope this helps.
Related
We have a Laravel 8 application.
We're using the standard Laravel Auth facade to retrieve the authenticated user.
Our User model has a few custom functions, the most important of which is a shorthand function, hasPermissionTo(). (The reason why is because we have a very custom RBAC setup.)
So in a lot of our controllers, we have something like this...
use Illuminate\Routing\Controller as BaseController;
class ExampleController extends BaseController
{
public function index()
{
if (\Auth::user()->hasPermissionTo('Management:View Users')) {
// do something.
}
// etc.
}
}
That's all well and good until we start running static analysis. We're using Larastan, which is giving me these errors:
------ -------------------------------------------------------------------------------------------
Line Http/Controllers/ExampleController.php
------ -------------------------------------------------------------------------------------------
48 Call to an undefined method Illuminate\Contracts\Auth\Authenticatable::hasPermissionTo().
This also makes sense because the Auth facade proxies Illuminate\Auth\AuthManager and Auth::user(), via __call() magic, normally resolves to Illuminate\Auth\SessionGuard::user() and that typehints this...
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
...
So finally, my question:
Where is the failure here? Do I need to a) configure my static analysis tool better, b) configure Laravel better to more accurately return a specific type, or c) do I need to add explicit if (Auth::user() instanceof User) { ... } clauses all throughout my code?
Is there a correct way to override one of the Laravel stock classes with a more specific one of my own to address more specific functionality? Is there way to type-hint the actual authenticated User into the function declaration so I can declare function index(User $authenticatedUser) and have Laravel autopopulate this in with a more specific type hint?
I understand that I could just add an exclusion for this particular issue in Larastan and move on with my life, but the error is designed to protect against a specific class of error--i.e. if I added Auth0 and replaced App\Model\User with Auth0\Login\User, then I would have an Authenticatable class that fails to run hasPermissionTo(), and I'd have to now fix a bunch of code.
Eventually, this is how we worked around the problem. We added a type-hint for Larastan, so it can infer that $user has this HasRolesContract trait which provides hasPermissionTo().
public function index()
{
/** #var \App\Traits\HasRolesContract */
$user = \Auth::user();
if ($user->hasPermissionTo('Management:View Users')) {
Hopefully this helps someone else!
(Thanks for the nudge, #djjavo)
I'm trying to remove a follower but the revokeFollower() method returns nothing and not working. Using the Laravel Befriended https://github.com/renoki-co/befriended package.
public function unfollowFollowers(Request $request){
$loginUser = Auth::user();
return $loginUser->revokeFollower($request['id']);
}
User.php
use Rennokki\Befriended\Traits\Follow;
use Rennokki\Befriended\Contracts\Following;
use Rennokki\Befriended\Scopes\FollowFilterable;
class User extends Authenticatable implements Following
{
use Notifiable,Follow,FollowFilterable;
}
On the README there is mentioned:
Note: Following, unfollowing or checking if following models that do not correctly implement CanBeFollowed and Followable will always return false.
Following the guide to implement the native mail verification of laravel.
Brings me an error.
Note please that i use MongoDB, therefore i'm using Jensseger/laravel-mongodb package
This is the error:
Class App\User contains 3 abstract methods and must therefore be declared abstract or implement the remaining methods (Illuminate\Contracts\Auth\MustVerifyEmail::hasVerifiedEmail, Illuminate\Contracts\Auth\MustVerifyEmail::markEmailAsVerified, Illuminate\Contracts\Auth\MustVerifyEmail::sendEmailVerificationNotification
I've already try to implement the methods inside my model and they seem to solve the problem. But it won't send any emails.
Here's what i've implemented im my User.php model
* Determine if the user has verified their email address.
*
* #return bool
*/
public function hasVerifiedEmail()
{}
/**
* Mark the given user's email as verified.
*
* #return bool
*/
public function markEmailAsVerified()
{}
/**
* Send the email verification notification.
*
* #return void
*/
public function sendEmailVerificationNotification()
{}
Here's my User.php model
namespace App;
use App\Company;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Jenssegers\Mongodb\Auth\User as Authenticatable;
class User extends Authenticatable implements MustVerifyEmail
{
use Notifiable;
protected $connection = 'mongodb';
Here's my web.php route file.
Route::get('/', function () {
return view('welcome');
});
Auth::routes(['verify' => true]);
Route::get('/home', 'HomeController#index')->name('home');
And here's my HomeController.php
public function __construct()
{
$this->middleware(['auth','verified']);
}
Here's my env file
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=25
MAIL_USERNAME=xxxxxxxxxxx
MAIL_PASSWORD=xxxxxxxxxxxx
MAIL_ENCRYPTION=tls
Like this the project work but it wont send emails. Do i need to put the logic inside the three method inside the User.php? If yes what should i put in it? I've no idea because if it's native and work like charm with SQL i don't really know how to get it work on my project
Hope someone has a solution for this.
Thanks
Easiest solution is to implement trait Illuminate\Auth\MustVerifyEmail which should be there, however it is not mentioned in the Laravel documentation. You can also override these methods by defining them in the model as you did. But hasVerifiedEmail and markEmailAsVerified methods should have some verification logic and return bool based on the API.
Edit:
I also forgot to mention that method sendEmailVerificationNotification should contain $this->notify(new Notifications\VerifyEmail); otherwise it won't use the Notifiable trait and thus not send any email. For more details take a look at the method in Laravel framework repository,
I am building a store so i could learn laravel.
Like most stores, users can add items to a cart but cannot checkout until they register.
How do i have the same route return a user name when authorized and a nothing when an authorized.
This seemed very easy to me at first:
#if(Auth::guest())
Nothing || or login/register buttons
#else
{{ Auth::user()->name }}
#endif
That works well when you have content that should only be visible to loyal users but for a store, you need users to see whats there to offer.
The problem is that, in my home controller, i need to add middleware auth in the constructor function so that Route::get('/',HomeController#index); returns a view and in the view use #if(Auth::guest()) ..., but adding this middleware means this route is not accessible if the user is not Authenticated and without it you get this issue.
So how do i have the same root route with Authenticated user data(if authenticated) without blocking the route from unauthenticated users?
If i am understanding what you are asking (Though i believe i dont quite fully get what you mean).
You want to use the Auth::user() or Auth::check() throughout your views? This should be available out of the box especially when you have used php artisan make:auth.
One way to achieve this would be to use view->share() in a service provider on the boot method, This will then make the $user variable or $isSignedIn variable available in all views.
For example in your App\Providers\AppServiceProvider
namespace App\Providers;
use App\User;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->share('isSignedIn', Auth::check());
view()->share('user', Auth::user() ?: new User());
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
If this is not going to help let me know and i can help towards getting the outcome you need.
- Update
On your HomeController can you try:
use App\User;
use Illuminate\Support\Facades\Auth;
and in your index() method can you add:
if(Auth::user()){
$user = Auth::user();
}else{
$user = new User();
// or you can use:
$user = Auth::guest();
// If you use $user = Auth::guest() you can remove the Use App\User;
}
return view('home', compact('user'));
See if that does anything for you?
I have a problem, I can not use policies in laravel 5.2.
I have 2 tables, students and tasks.
I try to apply a policy to prevent editing of a task by changing the url, but I always get the message This action is unauthorized although the task is the correct user.
Policy Code:
<?php
namespace App\Policies;
use App\Models\Student;
use App\Models\Task;
class TasksPolicy
{
public function edit(Student $student, Task $tasks)
{
return $student->id === $tasks->student_id;
}
}
Code in AuthServiceProvider.php
<?php
namespace App\Providers;
use App\Models\Task;
use App\Policies\TasksPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
Task::class => TasksPolicy::class
];
And then the call in the TaskController.php file:
public function edit($id)
{
$tasks = Task::findOrFail($id);
$this->authorize('edit', $tasks);
return view('tasks.edit', compact('tasks'));
}
I think the code is good because I've revised several times, but as I said earlier I always get the message This action is unauthorized although the task is to edit the user.
http://i.imgur.com/2q6WFb3.jpg
What am I doing wrong? As I can use the policy correctly?
you are using "===" which means that both side data and datatype will match.May be your data are matched,not datatype,you may try using "=="
public function edit(Student $student, Task $tasks)
{
return $student->id == $tasks->student_id;
}
Two things: one is the name of the method and the other is the order of parameters. The method name should be 'update', not 'edit' - these are predefined, at least in later versions of Laravel. You might be getting the authorization error because the name 'edit' is not recognized by Laravel, so the policy for update is never defined.
The order of arguments also matters. When there are parameters passed to policy methods, the User model has to be the first parameter, followed by all the others.
public function update(User $user, [... other objects...])
So, you'd have
update(User $user, Student $student, Task $tasks)
Laravel will inject the Authenticated User Model but other objects have to be passed directly.
$this->authorize('edit', $student, $tasks);
Hopefully that will work.
If your Student class extends User Class, you may be thinking that you can substitute Student for User in the method prototype. You can't do that - that's a different method altogether.