I have two environments in cakephp 3.9 , both same code and same SO etc... Both in AWS hosted. I have created an API that works fine in staging but not in production, I always get FALSE when the user login with the email and pwd to get the JWT token. The weird thing it is that it works perfectly in the same environment in staging.
In the endpoint, I have this
/**
* Get JWT token
*/
public function token()
{
$user = $this->Auth->identify();
$roleQuery = TableRegistry::getTableLocator()->get('UsersRoles');
// Get user role
$role = $roleQuery
->find()
->select(['role_id'])
->where(['user_id' => $user['id']])
->first();
if (!$user) {
// throw new UnauthorizedException('Invalid login details');
$this->set([
'success' => false,
'data' => [
"code" => 401,
'message' => 'Invalid login details',
],
'_serialize' => ['success', 'data']
]);
} else{
$tokenId = base64_encode(32);
$issuedAt = time();
$key = Security::salt();
// $email = $user['email'];
$this->set([
'msg' => 'Login successfully',
'success' => true,
// 'user' => $user,
'data' => [
'token' => JWT::encode([
'alg' => 'HS256',
'id' => $user['id'],
'sub' => $user['id'],
'iat' => time(),
'exp' => time() + 86400,
],
$key)
],
'_serialize' => ['success', 'data', 'key']
]);
}
}
}
And the configuration for this environment
'Api' => [
'auth' => [
'storage' => 'Memory',
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email'
],
],
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'Users',
// 'scope' => ['Users.status' => 1],
'fields' => [
'id' => 'id'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
],
],
In the ApiController I have these two methods to load the components etc...
public function initialize(): void
{
parent::initialize();
$this->loadComponent('Security');
$this->loadComponent('RequestHandler');
$this->loadComponent('Auth', Configure::read('Api.auth'));
$this->Auth->allow([
'token'
]);
}
public function beforeFilter(Event $event): void
{
$this->Security->setConfig('unlockedActions', [
'token'
]);
}
I always get the same response in production
{
"success": false,
"data": {
"code": 401,
"message": "Invalid login details"
}
}
Well, after a few hours I fixed the problem. It was a very very stupid thing, I just forgot to add the https protocol to the URL in Rester (plugin similar to Postman) before call the endpoint, that's it!!!.
Related
i tried to create API using Laravel 8 and here are my code for register new user
public function register(Request $request)
{
$validasi = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'user_id' => 'unique:users',
'password' => 'required|string|min:8',
'foto_ktp' => 'file|mimes:png,jpg',
]);
try {
$fileName = time() . $request->file('foto_ktp')->getClientOriginalName();
$path = $request->file('foto_ktp')->storeAs('uploads/foto_ktp', $fileName);
$validasi['foto_ktp'] = $path;
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'user_id' => $request->id,
'foto_ktp' => $request->foto_ktp,
'password' => Hash::make($request->password),
]);
$user->save();
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'data' => $user,
'message' => 'Account Has Successfully Created',
'token' => $token,
'token_type' => 'Bearer',
'code' => 200
]);
} catch (\Exception $e) {
return response()->json([
'message' => 'Something wrong, user was not resgistered successfully',
'errors' => $e->getMessage(),
]);
}
}
when i tried the routes of API in Postman, the data will return like this
{
"data": {
"name": "test",
"email": "test#gmail.com",
"updated_at": "2023-01-02T06:54:01.000000Z",
"created_at": "2023-01-02T06:54:01.000000Z",
"id": 22,
"foto_ktp": {}
},
"message": "Account Has Successfully Created",
"token": "19|RXUZB40Oc35XCY4OMU6TPpqLJsmTRdFVpqsdNaS5",
"token_type": "Bearer",
"code": 200
}
foto_ktp will return {} and i checked it in database, foto_ktp field will store this data C:\xampp\tmp\php53D.tmp
I'm quite new in Laravel and i have tried to search any references but i haven't gotten it. Is there any suggestion what should i do? I used Laravel 8 for developing the API
I'm getting this error "message": "User does not have the right roles.", "exception": "Spatie\Permission\Exceptions\UnauthorizedException", I am using spatie package https://github.com/spatie/laravel-permission
This error occurs anytime I try accessing an api route protected with ['role:admin'] middleware. I'm using passport for API authentication and Spatie for ACL. I used multi guards. Everything works fine without the spatie middleware but I want to protect certain routes based on user roles
This is my config/auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'admin' => [
'driver' => 'eloquent',
'model' => Admin::class,
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
This is my kernel.php
protected $routeMiddleware = [
.......
'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middlewares\RoleOrPermissionMiddleware::class,
];
When registering a user, I assign the role of admin like this in my AuthController. The 'admin' role gets assigned to the User successfully but I still get "User does not have the required role" whenever I want to access an [role:admin] protected route.
public function registration(Request $request)
{
...........
$user = User::create($data);
$user->assignRole('admin');
$response = [];
$response['token'] = $user->createToken('api-application')->accessToken;
$response['user'] = [$user, $organization];
return response()->json($response, 202);
}
This is my user model
.......
protected $guard_name = 'api';
protected $table = 'users';
protected $fillable = [
'firstname',
'lastname',
'email',
'password',
'organization_id',
];
In my Controller VisitorsController I added the spatie role middleware to protect like this
public function __construct()
{
$this->middleware(['role:admin']);
}
public function index()
{
$visitor = Visitor::all();
return VisitorsResource::collection($visitor);
}
And in my api.php I have this
Route::middleware('auth:api')->prefix('V1')->group(function () {
........
Route::apiResource('/visitors', VisitorsController::class);
});
.........
Route::post('/register', [AuthController::class, 'registration'])->name('registration');
Have I provided enough information? And please what I'm I doing wrong?
I am currently developing an API with Laravel 7 and I want to authenticate users coming from different applications with Passport : 3 applications communicate with the API, so 3 different user tables.
It's working fine with the User model provided but when I use my own model, I can't login : it responds "Bad credentials" with the good credentials.
So my question is : Is it possible to use a different model from User provided and also multiple model at the same time for each APP/Client ?
Here is a diagram of the structure I want : Diagram
My App\User :
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable{
use Notifiable, HasApiTokens;
....
}
Here is my login function :
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email',
'password' => 'required|string'
]);
$credentials = request(['email', 'password']);
if(!Auth::attempt($credentials))
return response()->json([
'message' => 'Bad credentials'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->expires_at = Carbon::now()->addHours(1);
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
}
}
My config/auth
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'userstest',
],
'api' => [
'driver' => 'passport',
'provider' => 'userstest',
'hash' => false,
],
], 'providers' => [
'userstest' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
this is my behavior function in ShippingController :
public function behaviors()
{
return [
'access' => [
'class' => \yii\filters\AccessControl::className(),
'rules' => [
// deny all POST requests
// [
// 'actions' => ['index', 'create'],
// 'allow' => TRUE,
// ],
[
'actions' => ['index', 'create', 'init'],
'allow' => true,
'roles' => ['user2','user3'],
'denyCallback' => function()
{
redirect to address/index if user 2 cant access redirect to address/create if user3 cant access
//redirect here
}
],
// everything else is denied
],
],
];
}
how to handle this problem !?
i want redirect page to address/index if role :user2 cant access
and redirect to address/create if role : user3 cant access
I assume you are using the RBAC system in yii.
Check what config files for:
'authManager' => [
'class' => 'yii\rbac\DbManager',
],
or 'yii\rbac\PhpManager'.
Here is what worked for me:
'actions' => ['index', 'create', 'init'],
'allow' => false,
'roles' => ['user2','user3'],
'denyCallback' => function()
{
$user = Yii::$app->user;
if ($user->can('user2')) {
return Yii::$app->getResponse()->redirect(['/address/index']);
} else {
return Yii::$app->getResponse()->redirect(['/address/create']);
}
}
The 'allow' option of the rule should be set to false in order for denyCallback to be called.
You can see that at "yiisoft/yii2/filters/AccessControl.php" line 120.
I'm working in CakePHP 3.2 and writing an admin panel where only admin can login.
There is a separate table admins to store admin credentials. There is users table also which is used for users to register/login from main application.
I have to use admins table to login in admin panel.
What I have done is.
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Admins',
'action' => 'login',
'plugin' => 'Admins'
],
'loginRedirect' => [
'controller' => 'ServiceRequests',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Admins',
'action' => 'login'
],
'authenticate' => [
'Form' => [
'userModel' => 'Admin',
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
]
]);
}
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
}
}
AdminsController.php
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
use App\Controller\AuthComponent;
/**
* Admins Controller
*
* #property \App\Model\Table\AdminsTable $Admins
*/
class AdminsController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow('add');
// Pass settings in using 'all'
$this->Auth->config('authenticate', [
AuthComponent::ALL => ['userModel' => 'Members'],
'Basic',
'Form'
]);
}
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid username or password, try again'));
}
}
public function logout()
{
return $this->redirect($this->Auth->logout());
}
}
But this is not working. and gives Error: Class App\Controller\AuthComponent' not found
Also I want to restrict access to all controllers and actions without login. Thats why there is no $this->Auth->allow() in AppsController.php
use Cake\Controller\Component\AuthComponent;