Below is my Controller Action method. You can see I passed a param of Request Class to validate before going to save the data in database
public function store(RoleRequest $request)
{
}
My Request class is below.
class RoleRequest extends Request
{
private $Role;
public function __construct(IRole $_role) {
$this->Role = $_role;
}
public function authorize()
{
return true;
}
public function rules()
{
return [
'Role' => 'required|max:20|min:4,
];
}
}
Above code works perfectly when I run it through web page(blade).
I created one more controller for API to Send save request. Below is the code
class RoleApiController extends Controller
{
public function store(RoleRequest $request)
{
}
}
Issue comes, when I type just 1 char for role name and the Request class impose validation and I get 404 error This time I am sending request from Postman Extension in Chrome.
Error Details
The Validation Request class checks if your request is an ajax request or a normal request.
If it's a normal request it does: redirect()->back() with the validation messages in the session.
If it's an ajax request it shows a json object with the validation messages in it.
Frontend frameworks/libraries like for example jQuery add a header to an ajax request to let the backend know it's an ajax request. Laravel checks this header to decide what to do (using the isAjax or wantsJson methods).
Postman does not automatically send this header. So you should add one of the following headers manually:
Accept: application/json
X-Requested-With: XMLHttpRequest
Here is a screenshot of postman as an example:
Related
I would like to add HTTP basic authentication to my Yii2 application in which the username/password is stored in the Yii configuration file - for exactly one user, no DB authentication.
I have enabled authentication for my controller by adding behaviors function:
public function behaviors()
{
return [
'basicAuth' => [
'class' => \yii\filters\auth\HttpBasicAuth::className(),
'auth' => function ($username, $password) {
if ($username=='api') {
return new SimpleApiUser();
} else {
return null;
}
},
],
];
}
And I was required to create class, that implements IdentityInterface, that is why I have class:
class SimpleApiUser implements IdentityInterface {
public static function findIdentity($id)
{
return null;
}
public static function findIdentityByAccessToken($token, $type = null)
{
return null;
}
public function getId()
{
return 1;
}
public function getAuthKey()
{
return 1;
}
public function validateAuthKey($authKey)
{
return true;
}
}
That is fine, the application asks for username/password in the case of the first request, but then it managed to store the authentication somehow in some internal session and it does not required repeated authentication for each new request be it made from the browser (which my add sessions) or be it from Postman (which certainly does not keep sessions). Is it possibly to modify user class to require to provide username and password with each new request?
I've tried to play around a bit with your code.
First, your code is enough to require the basic auth to be part of every request. If the Authorization header is not present in request the yii will return 401 Unauthorized. So your implementation is already doing what you need.
There are reasons why user is not required to enter username/password each time.
For web browsers:
The credentials are saved for session and the browser will send them automatically in each subsequent request without prompting them again from user.
For postman: The authorization is stored for request as long as you don't manually remove the authorization settings it will be sent as part of each request.
If you want to force users to manually enter username/password with each request you can extend the HttpBasicAuth component to pretend that the authorization was not part of request for every other request like this
use Yii;
use yii\filters\auth\HttpBasicAuth;
class MyHttpBasicAuth extends HttpBasicAuth
{
const SESSION_KEY = 'authForced';
private $session;
public function __construct($config = [])
{
parent::__construct($config);
$this->session = Yii::$app->session;
}
public function authenticate($user, $request, $response)
{
if ($this->session->has(self::SESSION_KEY)) {
$this->session->remove(self::SESSION_KEY);
return parent::authenticate($user, $request, $response);
}
$this->session->set(self::SESSION_KEY, true);
return null;
}
}
But this will require sessions to work so it can only be used with browsers. It won't work well for API. For postman this implementation would make every other request fail with 401 Unauthorized. It would fail same way for api that will work with cookies and it would fail each request for api that wouldn't work with cookies.
Side note: The postman does keep/send cookies so sessions works with postman.
I have a issue, after i eliminate cors policy on laravel i sending some json data to check respond. But nothing happens...
I sending request by axios using react.js, i sending json data collected from state.
and now i trying to collect that data by laravel, but that is hardest patch.
already try something like that:
$content='test';
return Response::$content;
or just echo 'test' but nothing comes...
My code is inside controller.
class testRequest extends Controller
{
public function show(Request $request)
{
//$data = $request->json()->all();
// $experience = $data->experience;
$content='test';
return Response::$content;
}
}
for now i expect to get respond like 'test' but after that i will need to send a link to file path for respond.
the Response::$content is just wrong... the :: operator is used to access static member functions or attributes of the Response class... you should do something like this:
return Response::json(['test' => $content]);
or
return response()->json(['test' => $content]);
in order to respond with a JSON document.
My application uses ajax to request data. I'm using Symfony2, and when the session expires and I make a request with ajax, the login form is shown inside the main area on my application, and not as another view as should be. How can solve this problem. Thanks
I would suggest creating event listener which will be listening for every request:
services.yml:
your_request_listener:
class: Acme\AppBundle\EventListener\RequestListener
arguments: [#security.token_storage]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onRequest }
In this event listener I would check for type of request so this would be only Ajax request listener. When request is ajax type then I would check if session has expired - if so, I would create response which will be valid response for ajax request (i.e. JsonResponse) and set this response to be sent to user.
class RequestListener
{
private $tokenStorage;
public function __construct(TokenStorageInterface $tokenStorage)
{
$this->tokenStorage = $tokenStorage;
}
public function onRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
if (!$request->isXmlHttpRequest()) {
return; //we dismiss requests other than ajax
}
//now you check if user is authenticated/session expired/whatever you need
$token = $this->tokenStorage->getToken();
if ($token === null) {
//now you create response which you would expect in your js doing ajax, for example JsonResponse
$response = new JsonResponse(); //you should give some content here
$event->setResponse($response); //now you override response which will be sent to user
}
}
}
You could use an entry point in which you verify if the request is an AJAX request. If yes, you return a JSON response with 401 HTTP status code. Then in JS code you verify the HTTP status code. If 401, then redirect to login page.
You can read my post here with the complete solution (see my own answer to my own question). This solution is based on this excellent post.
As it's stated in docs, if AJAX validation fails you get json response:
If validation fails, a redirect response will be generated to send the user back to their previous location. The errors will also be flashed to the session so they are available for display. If the request was an AJAX request, a HTTP response with a 422 status code will be returned to the user including a JSON representation of the validation errors.
But I'd prefer partial view with flashed error which is default for non AJAX.
So is it possible to emulate non AJAX or turn off AJAX without rebuilding source or some other awkwardness?
BTW, culprit function is buildFailedValidationResponse.
I got into a similar problem these days and ended up overwriting a method as well.
Under Laravel 5.1.20, i had to copy method response from class Illuminate\Foundation\Http\FormRequest into class App\Http\Requests\Request, and just like your answer, changed
if ($this->ajax() || $this->wantsJson()) {
with
if ($this->wantsJson())) {
This is the complete method in App\Http\Requests\Request class
public function response(array $errors)
{
if (!$this->pjax() && ($this->ajax() || $this->wantsJson())) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
Managed to solve the problem with brute force. Just overwritten the trait method in AuthController. Bad feel about that.
protected function buildFailedValidationResponse(Request $request, array $errors)
{
if (/*$request->ajax() ||*/ $request->wantsJson()) { return new JsonResponse($errors, 422);
}
I have a custom Request Class on Laravel 5 which handles form inputs (POST). the thing is, I want to use the same request class for a GET method but instead of redirecting the user back to the original request URL (which causes an infinite) loop I want to throw an exception (if the request is not valid), how is that possible?
In your custom Request class, you can override the failedValidation method that is defined in the FormRequest class.
I.e. place this method in your Request class:
protected function failedValidation(\Illuminate\Validation\Validator $validator) {
throw new \Exception('Error processing request');
}
Overriding the response() method can also be used to return a preferred response, personally I have used this to return the errors in JSON form, all that was required to do this was to return a JsonResponse with the errors and response code:
public function response(array $errors)
{
return new JsonResponse($errors, 422);
}
You can add something like this in your request method:
if (Request::isMethod('get'))
{
//Here you can add your custom exception.
}
You can see the documentation for more info about this: http://laravel.com/docs/5.0/requests#other-request-information