How to generate token with JWT on Laravel 9 - authentication

The problem is that it does not generate the TOKEN, throwing the following error
TypeError: Lcobucci\JWT\Token\Builder::relatedTo(): Argument #1 ($subject) must be of type string, null given
When I make the request through the post verb, it performs all the previous validation but when it comes to generating the token, the error occurs.
`
public function login(Request $request)
{
$credentials = $request->only('usuario', 'password');
$validator = Validator::make($request->all(), [
'usuario' => 'required',
'password' => 'required'
]);
if ($validator->fails()) {
return response()->json([
'message' => $validator->errors(),
'token' => null
], 404);
}
$user = usuarios::where('usuario', $request->usuario)->first();
if (!$user) {
return response()->json([
'message' => 'Usuario no registrado.',
'token' => null
], 401);
}
$isValid = Hash::check($request->password, $user->password);
if (!$isValid) {
return response()->json([
'message' => 'ContraseƱa incorrecta.'
]);
}
$token = JWTAuth::fromUser($user);
return response()->json([
'message' => 'Usuario logueado correctamente',
'token' => $token
]);
}
`
And my code mode is this
`
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
//AƱadimos la clase JWTSubject
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Notifications\Notifiable;
class usuarios extends Model implements JWTSubject
{
use HasFactory, HasApiTokens, Notifiable;
protected $table = 'usuarios';
protected $fillable = [
'tipo_usuario',
'acceso_pv',
'nombre',
'usuario',
'password',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
public $timestamps = false;
}
`

Related

Laravel 9 error route | The GET method is not supported

I am having a problem fetching a list of certain customers (authenticated users) via API. When I use this route in Postman I receive the following error.
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException:
The GET method is not supported for this route. Supported methods:
POST. in file
D:\api\vendor\laravel\framework\src\Illuminate\Routing\AbstractRouteCollection.php
on line 118
api.php
Route::post('/register', [UserAuthController::class, 'register']);
Route::post('/login', [UserAuthController::class, 'login'])
->name('login');
Route::apiResource('/customer', CustomerController::class)
->middleware('auth:api');
Controller
class CustomerController extends Controller
{
public function index()
{
$customers = Customer::all();
return response([ 'customers' =>
CustomerResource::collection($customers),
'message' => 'Successful'], 200);
}
public function store(Request $request)
{
$data = $request->all();
$validator = Validator::make($data, [
'first_name'=>'required|max:120',
'email'=>'required|email|unique:users',
'password'=>'required|min:6'
]);
if($validator->fails()){
return response(['error' => $validator->errors(),
'Validation Error']);
}
$customer = Customer::create($data);
return response([ 'customer' => new CustomerResource($customer),
'message' => 'Success'], 200);
}
public function show(Customer $customer)
{
return response([ 'customer' => new CustomerResource($customer),
'message' => 'Success'], 200);
}
public function update(Request $request, Customer $customer)
{
$customer->update($request->all());
return response([ 'employee' => new CustomerResource($customer),
'message' => 'Success'], 200);
}
public function destroy(Customer $customer)
{
$customer->delete();
return response(['message' => 'Customer deleted']);
}
}
I solved this problem by adding Accept|json/application in headers of Postman.

Lumen JWT Auth always return 401 in other route after login success

I have lumen + jwt restapi with custom users table (ex : pengguna) with nomor as primary key and tgl_lahir as password..there is no problem with api/login and it's generate a token but when i try with other route such as api/buku, the return always 401 unauthorized although the authorization header contains valid token after login
my models like
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Laravel\Lumen\Auth\Authorizable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
use Authenticatable, Authorizable;
protected $primaryKey = 'nomor';
protected $table = 'pengguna';
public $timestamps = false;
protected $fillable = [
'nomor','nama','alamat'
];
protected $hidden = [
'tgl_lahir ',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}
my BukuController
<?php
namespace App\Http\Controllers;
use App\Buku;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class BukuController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function showAllBuku()
{
return response()->json(Buku::all());
}
}
my routes
$router->group(['prefix' => 'api'], function () use ($router) {
$router->post('login', 'AuthController#login');
$router->get('buku', ['uses' => 'BukuController#showAllBuku']);
});
config/auth.php
<?php
return [
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\User::class
]
],
];
the existing pengguna table don't allowed created ID field like lumen/laravel auth, if i commented code in Middleware\Authenticate like :
public function handle($request, Closure $next, $guard = null)
{
//if this block commented is working
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
return $next($request);
}
it's working..is there another way for my case?thanks for your help
sorry my mistake, my problem solved by add this in user model
public function getAuthIdentifierName(){
return $this->nomor;
}
public function getAuthIdentifier(){
return $this->{$this->getAuthIdentifierName()};
}

How to override this function to store data in DB?

In BroadcastServiceProvider.php I've got data when user joins the channel and I would like to store it to DB. I am wondering how to override this storeUser() function to make it work (I've used this function before but it was in other circumstances).
public function storeUser() {
UserInfo::create([
'ip' => Request::ip(),
'name' => Auth::user()->name
]);
}
BroadcastServiceProvider.php
Broadcast::channel('chat', function ($user) {
$ip = Request::ip();
if (auth()->check()) {
return [
'id' => $user->id,
'ip' => $ip,
'name' => $user->name
];
}
});
Update the UserInfo model to have the storeUser method.
class UserInfo
{
public static function storeUser() {
UserInfo::create([
'ip' => Request::ip(),
'name' => Auth::user()->name
]);
}
Then you can call it in the broadcaster
Broadcast::channel('chat', function ($user) {
$ip = Request::ip();
if (auth()->check()) {
UserInfo::storeUser();
return [
'id' => $user->id,
'ip' => $ip,
'name' => $user->name
];
}
});
You can also call it in the same way UserInfo::storeUser(); in the users controller where ever you need it.

Change Password in hashed function in laravel 5.6

I want to change my password which is been hashed while saving.
How can i change the password?
'password' => Hash::make($data->password).
My Controller
$request->validate([
'oldpass' => 'required',
'password' => 'required|alphaNum|min:6',
'password_confirmation' => 'required|same:newpass',
]);
$id = $request->id;
$users = Auth::user()->whereId($id)->get();
foreach ($users as $user) {
if ($oldpass == $user->password) {
$user->update([
'password' => Hash::make($request->newpass)
]);
return view('\balance');
} else {
return 'error';
}
}
You should use Hash::check($old_password, $hashed_password), something like this:
public function passwordChange(Request $request, User $user_name) {
// find the loggedin user
$user = User::find(Auth::user()->id);
// validate rules
$validator = Validator::make($request->all(), [
'old_password' => 'required|min:6',
'password' => 'required_with:password_confirmation|required|min:6',
'password_confirmation' => 'confirmed|required|min:6',
]);
// what to do if validator fails
if ($validator->fails()) {
return redirect($user->user_name . '/settings')->withErrors($validator)->withInput();
} else {
$old_password = $request->input('old_password');
$new_password = $request->input('password');
$hashed_password = Auth::user()->password;
// checking the old pass with new one
if (Hash::check($old_password, $hashed_password)) {
$user->update([
'password'=> Hash::make($new_password)
]);
return redirect($user->user_name . '/settings')->with('success', 'Your Password updated.');
} else {
return redirect($user->user_name . '/settings')->with('success', 'Your Old password is wrong!');
}
}
}
Please also notice 'password' => 'required_with:password_confirmation and 'password_confirmation' => 'required|same:newpass' on validator. Hope it helps.

Can't authenticate with different table

I've changed the auth.php file in order to authenticate my users according to authors table. But I keep getting No account for you when I'm running test route.
auth.php
<?php
return array(
'driver' => 'eloquent',
'model' => 'Author',
'table' => 'authors',
'reminder' => array(
'email' => 'emails.auth.reminder', 'table' => 'password_reminders',
),
);
routes.php
Route::get('test', function() {
$credentials = array('username' => 'giannis',
'password' => Hash::make('giannis'));
if (Auth::attempt($credentials)) {
return "You are a user.";
}
return "No account for you";
});
AuthorsTableSeeder.php
<?php
class AuthorsTableSeeder extends Seeder {
public function run()
{
// Uncomment the below to wipe the table clean before populating
DB::table('authors')->delete();
$authors = array(
[
'username' => 'giannis',
'password' => Hash::make('giannis'),
'name' => 'giannis',
'lastname' => 'christofakis'],
[
'username' => 'antonis',
'password' => Hash::make('antonis'),
'name' => 'antonis',
'lastname' => 'antonopoulos']
);
// Uncomment the below to run the seeder
DB::table('authors')->insert($authors);
}
}
Addendum
I saw in another post that you have to implement the UserInterface RemindableInterface interfaces. But the result was the same.
Author.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class Author extends Eloquent implements UserInterface, RemindableInterface {
protected $guarded = array();
public static $rules = array();
public function posts() {
return $this->hasMany('Post');
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return "giannis#hotmail.com";
}
}
You don't need to Hash your password when you are using Auth::attempt(); so remove Hash::make from routes
Route::get('test', function() {
$credentials = array('username' => 'giannis',
'password' => 'giannis');
if (Auth::attempt($credentials)) {
return "You are a user.";
}
return "No account for you";
});
and it will work like a charm!