CSRF token mismatch while uploading image using ajax in CakePHP 3.6 - ajax

I have tried
class UsersController extends AppController
{
public function beforeFilter(Event $event)
{
$this->getEventManager()->off($this->Csrf);
}
public function ajaxEdit($id = null)
{
$this->autoRender = false;
debug($id);
debug($this->request->getData());
}
And I am using ajax code
$(document).ready(function(){
$('#user-profile').change(function(){
$('.loader-body').show();
var form = $('#user-profile-image')[0];
var formData = new FormData(form);
var tutorial_id = $('#user-file-id').val();
$.ajax({
url :"/users/ajax-edit/"+tutorial_id,
method:"POST",
data:formData,
contentType:false,
cache: false,
processData:false,
success:function(data){
let parseData = $.parseJSON(data);
if (parseData.status === true) {
location.reload();
var value = parseData.url;
console.log(value);
} else {
alert(parseData.message);
}
}
});
});
});
I have followed help from these links
CakePHP ajax CSRF token mismatch
2 https://book.cakephp.org/3.0/en/controllers/components/csrf.html
Getting CSRF token mismatch (see attached image)
https://i.stack.imgur.com/FsVZu.png

First of all if your are using POST method in your ajax call then you should send tutorial_id as data instead of sending it in the url.
You can resolve this by sending you CSRF token through a special X-CSRF-Token header in your ajax call.
https://book.cakephp.org/3.0/en/controllers/components/csrf.html
beforeSend: function (xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('[name="_csrfToken"]').val());
},
OR
You can disable CSRF component[Not recommended by the Cakephp] for your ajax action like:
public function beforeFilter(Event $event) {
if (in_array($this->request->action, ['ajaxEdit'])) {
$this->eventManager()->off($this->Csrf);
}
}

Related

Not getting post data in controller from ajax

I am posting my form data to A controller but when I post data I am not getting in the controller when I call print_r($_POST); its returning null array I don't know what I have missed
Please let me know what inputs you want from my side
var data2 = [];
data2['user_firstname'] = user_firstname;
data2['user_lastname'] = user_lastname;
data2['user_phone'] = user_phone;
data2['user_email'] = user_email;
data2['user_username'] = user_username;
data2['user_password'] = user_password;
console.log(data2);
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
type: "POST",
url: "http://localhost/shago/register/submit",
data: { 'data2': data2 },
// dataType: "text",
success: function(resultData) { console.log(resultData); }
});
controller code
public function submit()
{
print_r($_POST);
}
You can use the following
public function submit(Request $request)
{
dump($request);
}
Try adding Request as parameter on your submit function
public function submit(Request $request)
{
print_r($request);
}
Also, do you really need to pass your information as an array?
You could just create a new object and pass that as well.
var data2={
'user_firstname': user_firstname,
'user_lastname': user_lastname,
'user_phone': user_phone,
'user_email': user_email,
'user_username': user_username,
'user_password': user_password
};
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
type: "POST",
url: "http://localhost/shago/register/submit",
data: data2,
success: function(resultData) { console.log(resultData); }
});
You need to inject Request Class injection into submit method. This can help you:
public function submit(\Illuminate\Http\Request $request)
{
dd($request->all()); // will print all data
}
of if you don't want to inject Request then this code may helps you
public function submit()
{
dd(request()->all()); // will print all data
}
Good Luck !!!
Maybe the request was intercepted by Laravel CSRF Protection policy.In order to prove it, you should add request URL in VerifyCsrfToken middleware file, like following:
protected $except = [
'yoururl'
];
If you can get the data you expect in your controller, then I am right.
Thanks all i found error in when i am sending array data now i have modified code and its working fine
see code
$.ajax({
url: "register/submit",
type: "post",
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
data: {'user_firstname':user_firstname,'user_lastname':user_lastname,'user_phone':user_phone,'user_email':user_email,'user_username':user_username,'user_password':user_password},
success: function(result){
console.log(result);
}
});
}

Asp.net Core 2.0 Razor Pages Ajax Post

I am trying to just jquery ajax call to retrieve a list of users from a Razor page.
Users.cshtml.cs page:
public ActionResult OnPostList(string FirstName, string LastName,string IsActive)
{
var data=(from s in _db.SecurityUser
where s.FirstName.Contains(FirstName) && s.LastName.Contains(LastName) && (IsActive=="" || (IsActive =="Y" && s.IsActive==true) || (IsActive == "N" && s.IsActive == false))
select s).OrderBy(s=>s.FirstName);
return new JsonResult(data);
}
JS Call:
$.ajax({
type: "POST",
url: "/Security/Users?handler=List",
data: JSON.stringify({
FirstName: $("#txtFirstName").val(),
LastName: $("#txtLastName").val(),
IsActive: $("#ddActive").val()
}),
contentType: "application/json",
dataType: "json",
success: function (response) {
var d = response.d;
var tblBody = $("#tblUsers > tbody");
tblBody.empty();
$.each(d, function (i, item) {
var modifiedDate = new Date(parseInt(item.ModifiedDate.substr(6)));
var $tr = $('<tr>').append(
$('<td>').html("<a href='javascript:void(0)' onclick='fnDialogShow(" + item.UserID + ")'>Edit</a>"),
$('<td>').text(item.FirstName),
$('<td>').text(item.LastName),
$('<td>').text(item.IsActive ? "Yes" : "No")
).appendTo(tblBody);
});
},
failure: function (response) {
alert(response.d);
}
});
When it calls I get a 400 error back. Trying to figure out what I am doing wrong.
Your URL formation for Ajax request is correct. One thing to note down is, Razor Pages are designed to be protected from (CSRF/XSRF) attacks. Hence, Antiforgery token generation and validation are automatically included in Razor Pages. I believe that is the problem here. Your page may have antiforgery token present on the page if you have form tag in your HTML. But you need to pass the same in your Ajax request.
First, add antiforgery token using #Html.AntiForgeryToken(), if not present.
Then, modify your Ajax request to send the same in request header.
Like,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
Read this post Handle Ajax Requests in ASP.NET Core Razor Pages to know more about making ajax request with ASP.NET Core razor pages.
for .net core 2.1 the solution from this blog helped
https://www.thereformedprogrammer.net/asp-net-core-razor-pages-how-to-implement-ajax-requests/
if the page does not contain form with method post, add antiforgery token #Html.AntiForgeryToken()
and you can start to fire ajax request, important part is to set headers here.
$.ajax({
type: "POST",
url: "/Customers?handler=Delete",
data: { id: id },
contentType: "application/json; charset=utf-8",
dataType: "json",
// AntiforgeryToken is required by RazorPages
headers: {
RequestVerificationToken: $('input:hidden[name="__RequestVerificationToken"]').val()
}
})
.done(function () {
alert("success");
})
.fail(function () {
alert("error");
});
By default, Razor Pages are designed to be protected CSRF attacks.
You must properly inject the antiforgery token into your ajax request.
See the Documentation.
In ASP.NET Core 2.0 it looks like this...
First place this code into the top of your razor view:
// At the top of your page
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
#functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
Then in your ajax request, set the token header.
$.ajax({
type: "post",
headers: {
"RequestVerificationToken": '#GetAntiXsrfRequestToken()'
},
url: '#Url.Action("Antiforgery", "Home")',
success: function (result) {
alert(result);
},
error: function (err, scnd) {
alert(err.statusText);
}
});
Mark your OnPostList with HttpPost attribute and change your URL in ajax call to /Security/OnPostList
add [HttpPost] in Action
[HttpPost]
public ActionResult OnPostList(string FirstName, string LastName,string IsActive)
{
var data=(from s in _db.SecurityUser
where s.FirstName.Contains(FirstName) && s.LastName.Contains(LastName) && (IsActive=="" || (IsActive =="Y" && s.IsActive==true) || (IsActive == "N" && s.IsActive == false))
select s).OrderBy(s=>s.FirstName);
return new JsonResult(data);
}
Used this Script in Users.cshtml.cs
<script>
var url='#(Url.Action("OnPostList","ControllerName"))';
var firstName= $("#txtFirstName").val();
var lastName= $("#txtLastName").val();
var isActive= $("#ddActive").val();
$.post(Url,{FirstName:firstName,LastName=lastName,IsActive=isActive},function(data){
var d = data.d;
var tblBody = $("#tblUsers > tbody");
tblBody.empty();
$.each(d, function (i, item) {
var modifiedDate = new Date(parseInt(item.ModifiedDate.substr(6)));
var $tr = $('<tr>').append(
$('<td>').html("<a href='javascript:void(0)' onclick='fnDialogShow(" + item.UserID + ")'>Edit</a>"),
$('<td>').text(item.FirstName),
$('<td>').text(item.LastName),
$('<td>').text(item.IsActive ? "Yes" : "No")
).appendTo(tblBody);
});
});
</script>
I had bad experiences with $.ajax, I used $.post instead.
I used validateAntiforgeryToken but its not necessary
$("#emailSubmit").click(function () {
$.post("/Projects/SendInvite",
{
Email: $("#email").val(),
Message: $("#message").val(),
__RequestVerificationToken: $('input[name="__RequestVerificationToken"]').val()
}
)
return false;
});
And this is net core action:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SendInvite(string Email, string Message)
{
//MailTest();
var json = new List<string>
{
Email,
Message
};
return new JsonResult(json);
}

Call a prestashop module with ajax

I have a PrestaShop module called 'MyMenu' and I want call this menu with an AJAX call.
My module is displayed in the hookFooter() method:
public function hookFooter()
{
$display = $this->display(__FILE__, 'megamenu.tpl', $smartyCacheId);
Tools::restoreCacheSettings();
return $display;
}
I want display with this script:
<div class="load_menu"></div>
<script>
$(document).ready(function (e) {
$.ajax({
method: "POST",
url: "../modules/MyMenu.php",
data: {},
success: function (data) {
$('.load_menu').html(data);
}
})
});
</script>
The best way is to do it via a front controller linked to your module.
You can call the url like this :
$link->getModuleLink('modulename','controller', $parameters);
// Parameters is an optionnal array, it can be empty
And for the controller, place a file like this ./modules/modulename/controllers/front/ajax.php with this kind of content :
class ModuleNameAjaxModuleFrontController extends ModuleFrontController
{
public function initContent()
{
$response = array('status' => false);
require_once _PS_MODULE_DIR_.'modulename/modulename.php';
$module = new ModuleName;
if (Tools::isSubmit('action')) {
$context = Context::getContext();
$cart = $context->cart;
switch (Tools::getValue('action')) {
case 'actionname':
$response = array('status' => true);
break;
default:
break;
}
}
// Classic json response
$json = Tools::jsonEncode($response);
$this->ajaxDie($json);
// For displaying like any other use this method to assign and display your template placed in modules/modulename/views/template/front/...
// $this->context->smarty->assign(array('var1'=>'value1'));
// $this->setTemplate('template.tpl');
// For sending a template in ajax use this method
// $this->context->smarty->fetch('template.tpl');
}
}
If you don't want to pass the url by the module, the js snippet should be like this.
$(document).ready(function(){
$.ajax({
type: "POST",
headers: { "cache-control": "no-cache" },
url : baseDir + 'modules/yourmodulename/yourfile.php',
data: {
token : token
},
success : function(data){
$('.load-menu').html(data)
}
});
});
Where yourmodulename is the name of your module and yourfile.php is the code where you retrieve the menu.
Don't forget to add to your data the token, it's to prevent a CSFR attack, obviously you have to check the token in your server side script as well.
In a new file at the module root, you can create a file "ajax.php"
require_once(MODULE_DIR.'MyMenu/mymenu.php');
if(Tools::getValue('token') !=
$mymenu = Module::getInstanceByName('mymenu');
$menu = $mymenu->hookFooter();
die($menu);
In your js, at the root of your module
<script>
$(document).ready(function (e) {
$.ajax({
method: "POST",
url: "./ajax.php",
data: {},
success: function (data) {
$('.load_menu').html(data);
}
})
});
</script>

Render partial view with AJAX-call to MVC-action

I have this AJAX in my code:
$(".dogname").click(function () {
var id = $(this).attr("data-id");
alert(id);
$.ajax({
url: '/Home/GetSingleDog',
dataType: 'html',
data: {
dogid: id,
},
success: function (data) {
$('#hidden').html(data);
}
});
});
The alert gets triggered with the correct value but the AJAX-call does not start(the method does not get called).
Here is the method that im trying to hit:
public ActionResult GetSingleDog(int dogid)
{
var model = _ef.SingleDog(dogid);
if (Request.IsAjaxRequest())
{
return PartialView("_dogpartial", model);
}
else
{
return null;
}
}
Can someone see what i am missing? Thanks!
do you know what error does this ajax call throws?
Use fiddler or some other tool to verify response from the server.
try modifying your ajax call as following
$.ajax({
url: '/Home/GetSingleDog',
dataType: 'string',
data: {
dogid: id,
},
success: function (data) {
$('#hidden').html(data);
}
error: function(x,h,r)
{
//Verify error
}
});
Also try
$.get("Home/GetSingleDog",{dogid : id},function(data){
$('#hidden').html(data);
});
Make sure, URL is correct and parameter dogid(case sensitive) is same as in controller's action method

Bind event after login

I have made a filter called auth that check if user is logged. If is not logged it redirect on the main page but if is a call ajax? I just checked if is it. If it is i just send an json status "no-log". Now i received my json response "no-log" on my client and i would like open a modal for ask login and password. The solution that i thougth was put easily for each ajax request an if statement to check if the response status is "no-log" and show the function of modal. BUT OF COURSE is not good for future update, I'm looking for a good solution where i can bind this event and if i want on the future add other status. Any suggest?
Route::filter('auth', function()
{
if (Auth::guest()) {
if ( !Request::ajax() ) {
Session::put('loginRedirect', Request::url());
return Redirect::to('/');
} else {
$status = "no-log";
return json_encode(array('status' => $status));
}
}
});
A example of call ajax
$(document).on("click", ".delete", function() { // delete POST shared
var id_post = $(this);
bootbox.confirm("Are you sure do want delete?", function(result) {
if (result) {
$.ajax({
type: "POST",
url: '/delete_post/' + USER,
data: { id_post: id_post.attr('id') },
beforeSend: function(request) {
return request.setRequestHeader("X-CSRF-Token", $("meta[name='token']").attr('content'));
},
success: function(response) {
if (response.status == "success") {
id_post.parents('div.shared_box').fadeOut();
}
},
error: function(){
alert('error ajax');
}
});
} else {
console.log("close");
}
});
});
After 10 days of exploring an idea I found a way to override ajax comportment:
It just need you replace every $.ajax() by a custom one.
If I re-use your code:
$(document).on("click", ".delete", function() { // delete POST shared
var id_post = $(this);
bootbox.confirm("Are you sure do want delete?", function(result) {
if (result) {
myCustomAjax({ // In place of $.ajax({
type: "POST",
...
Then this custom function allow you to add some action before or after each ajax callback:
For instance checking the JSON return value in order to decide if I trigger the success callback or I show a warning:
function myCustomAjax(options) {
var temporaryVariable = options.success;
options.success = function (data, textStatus, jqXHR) {
// Here you can check jqXHR.responseText which contain your JSON reponse.
// And do whatever you want
// If everithing is OK you can also decide to continue with the previous succeed callback
if (typeof temporaryVariable === 'function')
temporaryVariable(data, textStatus, jqXHR);
};
return $.ajax(options);
}
If you return a 401 for all not loggedin requests, you can use $.ajaxSetup to handle all ajax errors in your application.
$.ajaxSetup({
error: function(jqXHR, exception) {
if (jqXHR.status == 401) {
window.location = 'your-login-page';
}
}
});

Resources