Laravel Spatie Roles and permissions - error on Update - laravel

I need help for my Laravel application.
I use spatie roles and permissions.
When i create the user, assign roles is no problem. When i will update the same user, there is the following error:
[2019-12-06 08:44:36] local.ERROR: The given role or permission should use guard instead of `web`. {"userId":1,"exception":"[object] (Spatie\\Permission\\Exceptions\\GuardDoesNotMatch(code: 0): The given role or permission should use guard instead of web. at /home/vagrant/code/test/vendor/spatie/laravel-permission/src/Exceptions/GuardDoesNotMatch.php:12)
public function store(StoreUserRequest $request)
{
$user = $this->repo->create( $request->all());
$user->assignRole($request->roles);
return $user;
}
public function update(UpdateUserRequest $request, User $user)
{
$user = $this->repo->update($user, $request->all());
$user->assignRole($request->roles);
return $user;
}
I added protected $guard_name = 'web'; to the User Model but still the same problem.
What is wrong? Is there a problme with the userId?

On update method use syncRoles instead of assignRole

When you assign role for a user the model path App\User insert into table model_has_roles if you change the model folders spatie give you an error. I think this code may help you more.
don't missing add HasRoles
class User extends Authenticatable
{
use Notifiable, HasRoles;
...
}
make sure you import use App\User;
UserController
public function update(Request $request, $id)
{
$this->validate($request, [
'name' => 'required',
'email' => 'required|email|unique:users,email,'.$id,
'password' => 'same:confirm-password',
'roles' => 'required'
]);
$input = $request->all();
if(!empty($input['password'])){
$input['password'] = Hash::make($input['password']);
}else{
$input = array_except($input,array('password'));
}
$user = User::find($id);
$user->update($input);
DB::table('model_has_roles')->where('model_id',$id)->delete();
$user->assignRole($request->input('roles'));
return redirect()->route('users.index')
->with('success','User updated successfully');
}

Related

Laravel passport throwing error: 'Call to a member function createToken() on null'

So i'm trying to create an auth repository test using phpunit but i keep getting the error 'Call to a member function createToken() on null'. I think this is due to the RefreshDatabase trait but i'm installing passport on setup so i'm a bit lost. Any help is appreciated!
AuthRepository test
namespace Tests\Repository;
use App\Contracts\Auth;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthRepositoryTest extends TestCase
{
use RefreshDatabase;
protected $authRepository;
protected function setUp(): void
{
parent::setUp();
$this->artisan('passport:install');
$this->authRepository = app()->make(Auth::class);
}
/**
* Test Successful Login
*
* #return void
*/
public function testSuccessfulLogin(): void
{
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->replace(['name' => 'test', 'email' => 'test', 'password' => 'testing']);
$this->authRepository->register($request);
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->replace(['email' => 'test', 'password' => 'testing']);
$this->authRepository->login($request);
}
}
Test Case
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp(): void
{
parent::setup();
}
}
AuthRepository
<?php
namespace App\Repositories;
use App\Contracts\Auth;
use Illuminate\Support\Facades\Auth as Authenticate;
use App\User;
class AuthRepository implements Auth
{
public function Register($request)
{
$user = new User([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => bcrypt($request->input('password'))
]);
$user->save();
return $user;
}
public function Login($request)
{
$credentials = $request->all();
if (!Authenticate::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->save();
return $tokenResult;
}
}
This is happened because the controller is trying to get the user data and create a token based on that.
In your case (happened to me too), there was a user variable which pointing the request to get the user credential while the user data is unknown because the user is not yet logged in.
To be clear, please take a look at your code within this line:
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
To fix that, change the line of $user = $request->user() to this:
$user = User::whereEmail($request->email)->first();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;

How do I check User Role before Logging in A user with Spatie's Laravel-Permission?

I'm using Spatie's "Laravel Permission" Package for the ACL. Everything is working perfectly. I now want to allow only the User roles 2 and 3 to Login.
Previously, before using "Laravel Permission" package I had only this "role" column on my table and I could easily Log In a user with this line of code on Login Controller's credentials method.
protected function credentials(Request $request)
{
$credentials = $request->only($this->username(), 'password');
//$credentials['role'] = '1';
return $credentials;
}
$credentials = $request->only($this->username(), 'password');
$credentials['role'] = '1';
How do I allow Login only for the 2 and 3 User Roles?
You can override authenticated() in LoginController and check user role. Pretty simple.
protected function authenticated(Request $request, $user)
{
//Check user role, if it is not admin then logout
if(!$user->hasRole(['Admin', 'Super-Admin']))
{
$this->guard()->logout();
$request->session()->invalidate();
return redirect('/login')->withErrors('You are unauthorized to login');
}
}
You could go with the workaround as follow:
If you're using the default LoginController from the App\Http\Controllers\Auth folder, then override its attemptLogin() method that comes from the Trait used.
protected function attemptLogin(Request $request)
{
if( $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
) ) { // Credential auth was successful
// Get user model
$user = Auth::user();
return $user->hasRole([2, 3]); // Check if user has role ids 2 or 3
}
return false;
}
hasRoles() method comes from the HasRoles trait used for the User model.
Or you could override the Laravel credentials during login. In your default LoginController from the App\Http\Controllers\Auth folder, then override its credentials(Request $request) method that comes from the Trait used.
Override it to look something similar to this
protected function credentials(Request $request)
{
return [ 'email' => $request-> { this-> username() }, 'password' -> $request -> password, 'role_id' => [ '1', '2' ] ];
This is presuming you have a role_id in your user model. Worked for me.return

User Policy Problem When I define two User models

I'm using Policies in Laravel. When I use two user models in policy it would not access me! However, both $user and $player return me correct data, individually. How can I handle it? What is my mistake?
in Controller:
$this->authorize('modifyTournamentRegistration', $player);
in Policy:
public function modifyTournamentRegistration(User $user, User $player)
{
return $user->id === $player->id || $user->inRole('admin');
}
I found out that it is because of Input variable type in Policy. I added User class in AuthServiceProvider:
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
User::class => UserPolicy::class,
];
Then, I defined the function in UserPolicy:
public function modifyPlayerTournamentRegistration(User $user, User $player)
{
return $player->id === $user->id || $user->inRole('admin');
}
And used it in Controller:
$this->authorize('modifyTournamentRegistration', $player);
It works as well :)

How to remove Laravel Auth Hashing (to replace it by mysql hashing)?

I added registration, and I don't want to using laravels hash but mysql Hash (because I want existing users to still be able to connect).
So i do it step by step and for now I just try to register and then login without any hashing. The credentials are correct in my table but I get
"message":"The given data was invalid.","errors":{"email":["These credentials do not match our records."]}
I tried setting it in LoginController.php
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
public function username()
{
return 'email';
}
public function password()
{
return 'email';
}
public function setPasswordAttribute($password){
$this->attributes['password'] = $password;
}
public function Login(Request $request)
{
if(Auth::attempt(['email' => $request->email, 'pwd' => $request->password, 'password' => $request->password])){
$user = Auth::user();
$username = $user->nom;
return response()->json([
'status' => 'success',
'user' => $username,
]);
} else {
return response()->json([
'status' => 'error',
'user' => 'Unauthorized Access'
]);
}
}
}
I guess I should overwrite another function, but can't find out which one.
Could you please give me some help?
Altough what you're trying to achieve is considered unsecure, to remove Laravel's hashing for password, you need to add this to your User model :
public function setPasswordAttribute($password){
$this->attributes['password'] = $password;
}
and not in your controller, and be sure to remove the brcypt() methods in your RegisterController
To add your MySQL own hashing methods, update your controller to insert a RAW query while creating a user upon registration

Laravel 5.3 Authentication Issue

I am having issues grabbing the currently authenticated user in Laravel 5.3. More specifically, I am making a HTTP request to my api.php file, which has the route defined as api/test/create.
The controller code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Test;
class TestController extends Controller
{
public function store(Request $request) {
$this->validate($request, [
'test_name' => 'required',
'youtube_id' => 'required',
'is_live_test' => 'required',
]);
//Laravel 5.3 allows to get the user via request
$user = $request->user;
if($user) {
return 'We are logged in';
} else {
return 'We are not logged in';
}
return '';
}
}
Every time it returns 'We are not logged in'. To test this out, I referenced {{ Auth::check() }} in my blade file, and that returns as '1'. I am not quite sure why the Controller does not recognize the user is logged in; any ideas?
I have tried different variations of referencing the authentication, including importing the Facade and doing Auth::check(), Auth::user(), but it brings the same result regardless.
Get user object with:
$user = $request->user();
Or:
$user = auth()->user();
You can use:
Auth::user();
also
auth()->user();
also
$request->user();
You can use Auth::check() method directly in the Controller.
if (Auth::check()){
// User is logged in
// Do something with the Authenticated User.
}else
{
// User is not logged in
}
to get User Data do something like this
$user = Auth::user();
$userId = $user->id;
etc.

Resources