I am using Laravel 5.4 with JWTAuth & Dingo and for some reason I am now no longer able to make POST requests with Postman. This was working when I first set it up, but not I get the response 405 Method Not Allowed
This seems to have been raised a few times on here, but I can't seem to find a solution. I've cleared the route cache, and when i do api:routes the correct routes are in there.
Below is the routes file, and the controllers it should be sending too. I am only having the issue with the LeadController routes.
api.php
use Dingo\Api\Routing\Router;
/** #var Router $api */
$api = app(Router::class);
$api->version('v1', function (Router $api) {
$api->group(['prefix' => 'auth'], function(Router $api) {
//$api->post('signup', 'App\\Api\\V1\\Controllers\\SignUpController#signUp');
$api->post('login', 'App\\Api\\V1\\Controllers\\LoginController#login');
$api->post('recovery', 'App\\Api\\V1\\Controllers\\ForgotPasswordController#sendResetEmail');
$api->post('reset', 'App\\Api\\V1\\Controllers\\ResetPasswordController#resetPassword');
});
$api->group(['middleware' => 'jwt.auth'], function(Router $api) {
$api->get('protected', function() {
return response()->json([
'message' => 'Access to protected resources granted! You are seeing this text as you provided the token correctly.'
]);
});
$api->get('refresh', [
'middleware' => 'jwt.refresh',
function() {
return response()->json([
'message' => 'By accessing this endpoint, you can refresh your access token at each request. Check out this response headers!'
]);
}
]);
$api->post('lead/store', 'App\\Api\\V1\\Controllers\\LeadController#store');
$api->get('lead', 'App\\Api\\V1\\Controllers\\LeadController#index');
});
});
LeadController.php
namespace App\Api\V1\Controllers;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Tymon\JWTAuth\JWTAuth;
use App\Http\Controllers\Controller;
use Dingo\Api\Routing\Helpers;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Lead;
use App\User;
class LeadController extends Controller
{
use Helpers;
public function index(Lead $leads)
{
$leads = $leads->all();
$count = 0;
foreach($leads as $key => $lead){
$user = User::where('id', $lead->user_id)->first();
$leads[$count]['name'] = $user->name;
array_pull($leads[$count], 'user_id');
$count++;
}
return $leads;
}
public function store(Request $request)
{
$today = new Carbon();
$this->validate(request(), [
'owner' => 'required',
'bname' => 'required|min:3|max:255',
'tname' => 'max:255',
'created' => 'required|date|before_or_equal:today',
'update' => 'date'
]);
if(!$user = User::where('zoho_id', $request->get('owner'))->first())
return $this->response->error('invalid_owner', 500);
$lead = new Lead;
$lead->user_id = $user->id;
$lead->bname = $request->get('bname');
$lead->tname = $request->get('tname');
$lead->created_at = $request->get('created');
$lead->updated_at = $request->get('updated');
if($lead->save())
return $this->response->created();
else
return $this->response->error('could_not_create_lead', 500);
}
}
I found the answer, for this whilst I almost finished writing the question by stumbling upon the answer here:
https://laracasts.com/discuss/channels/laravel/dingo-api-and-postman-not-matching-post-request
Remove the trailing / from the request URL. So will leave this answer here, in the hopes it may prove useful to someone.
ie. http://api.someurl.app/api/lead/store?token=....
Perhaps, someone can suggest a way of allowing trailing / ??
Related
I'm doing a login and registration screen, the registration screen is perfect, but the login screen is giving me a headache to authenticate.
the registration is done, but as soon as I log in it gives this error...
"Undefined property: Illuminate\Support\Facades\Request::$email"
I don't know what else to do to make it work.
CONTROLLER:
<?php
namespace App\Http\Controllers;
use App\Models\Usuario;
use Illuminate\Support\Facades\Auth;
use Request;
class Usuarios extends Controller
{
public function cadastrar()
{
$usuario = new Usuario(Request::all());
$usuario->save();
return redirect('/')->with('mensagem_sucesso', 'Cadastro efetuado com sucesso!');
}
public function index()
{
return view('layout/cadastrousuario');
}
public function indexlogin()
{
return view('layout/login');
}
public function logar(Request $request)
{
if (Auth::attempt(['email' => $request->email, 'password' => $request-> password])) {
dd('voce esta logado');
} else {
dd('voce nao esta logado');
}
}
}
MODEL:
<?php
namespace App\Models;
use App\Models\Model\Request;
use DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Hash;
class Usuario extends Authenticatable
{
protected $table = 'usuario';
public $timestamps = false;
protected $fillable =
array(
"codigo",
"nome",
"email",
"apelido",
"senha",
"bloqueado",
"saldo",
"saldo_atual",
"admin"
);
use HasFactory;
}
ROUTE:
<?php
use App\Http\Controllers\Lancamentos;
use App\Http\Controllers\LancamentosSimplificado;
use App\Http\Controllers\Usuarios;
use Illuminate\Support\Facades\Route;
// Route = (rota)::get ou post = (method) ( '/home' = (link) , [Lancamentos = (controller) :: class, 'logar' = ( function) ;
Route::get('/', [Lancamentos::class, 'index']);
Route::get('/salvar', [Lancamentos::class, 'salvar']);
Route::get('/maisdetalhes/{codigo}', [Lancamentos::class, 'maisdetalhes']);
Route::get('/criarchat', [Lancamentos::class, 'criarchat']);
Route::post('/cadastrar', [Lancamentos::class, 'cadastrar']);
Route::post('/cadastrar-simplificado', [LancamentosSimplificado::class, 'cadastrar']);
Route::get('/criarchat', [LancamentosSimplificado::class, 'listar']);
Route::get('/chat/{codigo}', [Lancamentos::class, 'chat']);
Route::get('/chatcriado/{codigo}', [LancamentosSimplificado::class, 'chatcriado']);
Route::get('/cadastrar-usuario', [Usuarios::class, 'index']);
Route::post('/cadastrar-usuario', [Usuarios::class, 'cadastrar']);
Route::get('/login', [Usuarios::class, 'indexlogin']);
Route::post('/login', [Usuarios::class, 'logar']);
page image as soon as I click login
to start you have to make validations in the register function to be sure that the email address arrives well and is registered. i would start by modifying this function
public function cadastrar(Request $r)
{
$r->validate([
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'min:6',
'password_confirmation' => 'required_with:password|same:password|min:6',
'custom_field' => 'custom validation'
]);
$input = $r->all();
$input['password'] = Hash::make($r->password);
$utilisateur = Model::create($input); //the Model == Usuario;
return redirect('/')->with([
'message' => "Cadastro efetuado com sucesso!",
'alert-type' => 'success',
]);
}
this is just a code snippet, I don't pretend to say that it's exactly what you need.the next way is the login function
if (Auth::attempt(['email' => $r->email, 'password' => $r->password])) {
// The user is active, not suspended, and exists.
$user = Auth::user();
if($user->fcm_token != Null){
$token = $user->createToken('AUTH')->accessToken;
$user->remember_token = $token;
$user->device_token = $user->fcm_token;
$user->save();
$response = [
"data"=> [
'user'=> $user,
'token'=> $token,
],
'message_fr' => 'Utilisateur connecté avec succès',
'message_en' => 'User logged successfully',
];
return response()->json($response, 200);
}else{
$response = [
'message_fr' => 'Vous êtes peut-être un robot',
'message_en' => 'You may be a robot',
];
return response()->json($response, 422);
}
} else {
$response = [
'message_fr' => 'Veuillez vérifier vos informations de connexion',
'message_en' => 'Please check your login information',
];
return response()->json($response, 422);
}
since you put a validation on the register, you are sure that the email is not only present, but also conforms to the nomenclature of an email
these two methods presented are examples taken from my source code of an available project, Good luck to you
You are using the wrong Request class. Request (Illuminate\Support\Facades\Request) that is aliased in config/app.php is the Facade, static proxy, for the bound Request class instance, Illuminate\Http\Request. If you want an instance of a Request you need to be using Illuminate\Http\Request.
use Illuminate\Http\Request;
Now via dependency injection you will have an instance of the Request class (which has magic methods to access inputs via dynamic properties). If you keep what you have then you would not be asking for an instance via dependency injection and would have to use the Facade as a Facade:
public function logar()
{
...
$something = Request::input(...); // static call to Facade
...
}
When I am making a API call to the http://localhost/lvl53/public/api/getSongs using Postman I get the following error.
FatalErrorException
Doctrine\Common\Proxy\AbstractProxyFactory::getProxyDefinition(): Failed opening required.
https://i.stack.imgur.com/TNEhO.png
Here are my routes web.php
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::group(['middleware' => ['web','auth']], function () {
Route::get('/song', 'SongController#index')->name('song');
Route::get('/addSong', 'SongController#addSong')->name('addNewSong');
Route::post('/registerSong', 'SongController#create')->name('registerSong');
});
Route::get('/home', 'HomeController#index')->name('home');
Here is api.php
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Route::group(['middleware' => ['web']], function () {
Route::get('/getSongs', 'SongController#getSongs')->name('getSongs');
});
But if I add the API route getSongs to the Route::Group in web.php and after logging in make the call, then I am able to retrieve data.
Here's my SongController's getSongs method
public function getSongs(EntityManagerInterface $em)
{
$songs = $em->getRepository(SongEntity::class)->findAll();
$songList = [];
\Log::info(["Songs",$songs]);
foreach ($songs as $song){
$currentSong["artist"] = $song->getArtist();
$currentSong["title"] = $song->getTitle();
$currentSong["url"] = $song->getUrl();
array_push($songList, $currentSong);
}
return $songList;
/*return view('song.songs', ['songs' => Song::all()]);*/
}
In here when making the api call \Log doesn't create a log. How to retrieve data using the API?
PS: When I looked into error msg they say I have do advance configurations on doctrine, it doesn't make sense. Any help is highly appreciated.
PPS: Do you think it has do something with attaching a authenticated user to SongEntity when creating the SongEntity?
Here's what happens when creating a SongEntity.
protected function create(Request $request, EntityManagerInterface $em)
{
$user = Auth::user();
//\Log::info($user);
$data = $request->input();
$this->validate($request, [
'title' => 'required|string|max:255',
'artist' => 'required|string|max:255',
'url' => 'required|string|url|unique:App\Entities\SongEntity',
]);
$song = new SongEntity(
$data['title'],
$data['artist'],
$data['url'],
$user
);
$em->persist($song);
$em->flush();
/* Song::create([
'title' => $data['title'],
'artist' => $data['artist'],
'url'=> $data['url']
]);*/
return redirect('song');
}
I have a problem with Laravel 5.4 validator which is I'm trying to validate data comes from a mobile application but when validator fails it redirect to the home page. I need to prevent this redirect and return a json response with validation errors messages
Here's my route.php code
Route::group(['middleware' => 'web'], function() {
Route::post('/userSignUp', [
'uses' => 'UserController#userSignUp',
'as' => 'userSingUp'
]);
});
And this is my controller code
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\MessageBag;
class UserController extends Controller
{
public function userSignUp(Request $request){
$fullName = $request->input('fullName');
$email = $request->input('email');
$phone = $request->input('phone');
$password = $request->input('password');
$userType = $request->input('userType');
$profilePic = $request->input('profilePic');
$validator = $this->validate($request, [
'fullName' => 'required|max:255',
'email' => 'required|email',
'phone' => 'required'
]);
if ($validator->fails()) {
return response()->json($validator->messages(), 200);
}
}
}
So can anyone help me solving this issue I need to use a laravel 5.4 validator in a web service for a mobile application so I need to prevent the validator redirecting as it does in the above code it redirecting to home page when validation is failed
thanks in advance
if the validation fails when you call $this->validate($request,$rules) laravel will throw an exception and a failed validation response will be sent back by this method define in Illuminate\Foundation\Validation\ValidatesRequests :
/**
* Create the response for when a request fails validation.
*
* #param \Illuminate\Http\Request $request
* #param array $errors
* #return \Symfony\Component\HttpFoundation\Response
*/
protected function buildFailedValidationResponse(Request $request, array $errors)
{
if ($request->expectsJson()) {
return new JsonResponse($errors, 422);
}
return redirect()->to($this->getRedirectUrl())
->withInput($request->input())
->withErrors($errors, $this->errorBag());
}
So it seems that Laravel does handle that by checking $request->expectsJson() so you need to specify the Accept header in you request to JSON, then a JSON formatted response with code 422 will be returned.
return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->withCallback($request->input('callback'));
from the official doc https://laravel.com/docs/5.4/responses#json-responses
And maybe try to make your validation in your model directly
class User extends Eloquent
{
private $rules = array(
'fullName' => 'required|max:255',
'email' => 'required|email',
'phone' => 'required|numeric'
);
public function validate($data)
{
// make a new validator object
$v = Validator::make($data, $this->rules);
// return the result
return $v->passes();
}
}
and in your controller you can make
$new = Input::all();
$u = new User();
if ($b->validate($new))
{
}
else
{
}
I have a weird problem with my Laravel application, whereby this code gets called twice once the validation rules kick in. I have abstracted validation logic into a separate class, but no matter how I consume the API (tried using Postman, and with jQuery) it still appears to run twice with the output looking like this:
called{"email":["The email has already been taken."],"country":["The country must be a number."]}called{"email":["The email has already been taken."],"country":["The country must be a number."]}
I am only expecting one JSON response. I'm tearing my hair out, tried on two different connections and can't seem to work out why the custom request is called twice. This is a new Laravel app, so there isn't much code to conflict with it.
//Create User Request extends standard request. Handles Validation
public function __construct(CreateUserRequest $request){
$this->request = $request;
}
public function register()
{
try{
$array = DB::transaction(function(){
$email = $this->request->input('email');
$password = $this->request->input('password');
$companyName = $this->request->input('companyName');
$userName = $this->request->input('name');
$country = $this->request->input('country');
$company = Company::create([
'name' => $companyName,
'active'=>true,
'country_id'=>$country
]);
$user = User::create([
'company_id' => $company->id,
'name'=>'admin',
'email' => $email,
'password' => $password,
'active' =>true
]);
if( !$company || !$user )
{
throw new \Exception('User not created for account');
}
return compact('company', 'user');
});
$token = JWTAuth::fromUser($array['user']);
return Response::json(compact('token'));
}
catch( Exception $e )
{
return Response::json(['error' => $e->getMessage() ], HttpResponse::HTTP_CONFLICT );
}
}
Then the validation custom Request..
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Response;
class CreateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
public function response(array $errors)
{
// return Response::json(['errorg' => $errors ], 200 );
echo('called');
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'required|unique:users',
'password' => 'required',
'companyName' => 'required',
'name' => 'required',
'country' => 'required|numeric'
];
}
}
Interesting.
Try to remove CreateUserRequest $request parameter from __construct() and add it to your register() method like this: register(CreateUserRequest $request). And use your request by calling $request instead of $this->request.
I'm using dingo/api (that has built-in support for jwt-auth) to make an API.
Suppose this is my routes :
$api->group(['prefix' => 'auth', 'namespace' => 'Auth'], function ($api) {
$api->post('checkPhone', 'LoginController#checkPhone');
//Protected Endpoints
$api->group(['middleware' => 'api.auth'], function ($api) {
$api->post('sendCode', 'LoginController#sendCode');
$api->post('verifyCode', 'LoginController#verifyCode');
});
});
checkPhone method that has task of authorize and creating token is like :
public function checkPhone (Request $request)
{
$phone_number = $request->get('phone_number');
if (User::where('phone_number', $phone_number)->exists()) {
$user = User::where('phone_number', $phone_number)->first();
$user->injectToken();
return $this->response->item($user, new UserTransformer);
} else {
return $this->response->error('Not Found Phone Number', 404);
}
}
And injectToken() method on User Model is :
public function injectToken ()
{
$this->token = JWTAuth::fromUser($this);
return $this;
}
Token creation works fine.
But When I send it to a protected Endpoint, always Unable to authenticate with invalid token occures.
The protected Endpoint action method is :
public function verifyCode (Request $request)
{
$phone_number = $request->get('phone_number');
$user_code = $request->get('user_code');
$user = User::wherePhoneNumber($phone_number)->first();
if ($user) {
$lastCode = $user->codes()->latest()->first();
if (Carbon::now() > $lastCode->expire_time) {
return $this->response->error('Code Is Expired', 500);
} else {
$code = $lastCode->code;
if ($user_code == $code) {
$user->update(['status' => true]);
return ['success' => true];
} else {
return $this->response->error('Wrong Code', 500);
}
}
} else {
return $this->response->error('User Not Found', 404);
}
}
I used PostMan as API client and send generated tokens as a header like this :
Authorization:Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI5ODkxMzk2MTYyNDYiLCJpc3MiOiJodHRwOlwvXC9hcGkucGFycy1hcHAuZGV2XC92MVwvYXV0aFwvY2hlY2tQaG9uZSIsImlhdCI6MTQ3NzEyMTI0MCwiZXhwIjoxNDc3MTI0ODQwLCJuYmYiOjE0NzcxMjEyNDAsImp0aSI6IjNiMjJlMjUxMTk4NzZmMzdjYWE5OThhM2JiZWI2YWM2In0.EEj32BoH0URg2Drwc22_CU8ll--puQT3Q1NNHC0LWW4
I Can not find solution after many search on the web and related repositories.
What is Problem in your opinion?
Update :
I found that not found error is for constructor of loginController that laravel offers :
public function __construct ()
{
$this->middleware('guest', ['except' => 'logout']);
}
because when I commented $this->middleware('guest', ['except' => 'logout']); all things worked.
But if I remove this line is correct?
How should be this line for APIs?
updating my config/api.php to this did the trick
// config/api.php
...
'auth' => [
'jwt' => 'Dingo\Api\Auth\Provider\JWT'
],
...
As I mentioned earlier as an Update note problem was that I used checkPhone and verifyCode in LoginController that has a check for guest in it's constructor.
And because guest middleware refers to \App\Http\Middleware\RedirectIfAuthenticated::class and that redirects logged in user to a /home directory and I did not created that, so 404 error occured.
Now just I moved those methods to a UserController without any middleware in it's constructor.
Always worth reading through the source to see whats happening. Answer: The is expecting the identifier of the auth provider in order to retrieve the user.
/**
* Authenticate request with a JWT.
*
* #param \Illuminate\Http\Request $request
* #param \Dingo\Api\Routing\Route $route
*
* #return mixed
*/
public function authenticate(Request $request, Route $route)
{
$token = $this->getToken($request);
try {
if (! $user = $this->auth->setToken($token)->authenticate()) {
throw new UnauthorizedHttpException('JWTAuth', 'Unable to authenticate with invalid token.');
}
} catch (JWTException $exception) {
throw new UnauthorizedHttpException('JWTAuth', $exception->getMessage(), $exception);
}
return $user;
}