I use this code for a basic anthentification of REST API. Unfortunately, when the user/pass is wrong Google Chrome displays a popup. Firefox does not do that.
$.ajax({
type: "GET",
url: "/ad",
dataType: 'json',
async: false,
username: 'username',
password: 'password',
success: function (){
alert('success');
return false;
},
error: function(){
alert('error');
return false;
}
});
Edit 1 :
I use Laravel Framework
If you don't have server control, there is no (at least not known to me) way to prevent that. If you DO have server control you can do two things:
Change the response status code from standard 401 to something else. However, this is commonly not known as best practice since the status code does then not state the actual issue (authentication error).
Change the response header WWW-Authenticate: Basic realm="your_realm" to a custom value like WWW-Authenticate: x-Basic realm="your_realm" (Note the x-there!).
That should prevent any default login handling.
Update 1
As for using Laravel this would be an example of setting the correct response header WWW-Authenticate (changed Basic to x-Basic):
Route::filter('auth', function()
{
$credentials = ['email' => Request::getUser(), 'password' => Request::getPassword()];
if (!Auth::once($credentials)) {
$response = ['error' => true, 'message' => 'Unauthorized request'];
$code = 401;
$headers = ['WWW-Authenticate' => 'x-Basic'];
return Response::json($response, $code, $headers);
}
});
I think you can pass the username and password in the URL instead for HTTP authentication.
Give this a shot:
$.ajax({
type: "GET",
url: "http://username:password#whatever.com/ad",
dataType: 'json',
async: false,
success: function (){
alert('success');
return false;
},
error: function(){
alert('error');
return false;
}
});
Related
I am using Ajax to login a user into the system.
Ajax success will always run the else statement even if the server returns true Boolean.
In case the login credentials were valid the else statement would run and login failed will show up, but if I refresh the page the user will be logged in.
Basically the if(response) never gets ran even though it is true.
$(function(){
$('#loginButtonIdHead').click(function() {
$.ajax({
url: 'localhost/landing/login',
type: 'POST',
data: {
email: $('#defaultForm-email1').val(),
password: $('#defaultForm-pass1').val()
},
success:function(response) {
if(response){
$('#messageId').text("Login Successful");
} else {
$('#messageId').text("Login Failed");
}
}
});
});
});
The $.ajax() method uses anonymous functions for the success and error callbacks. This version is easier to write, and likely easier to maintain:
$(function(){
$('#loginButtonIdHead').click(function(){
$.ajax({
url: 'localhost/landing/login',
type: 'POST',
data:
{
email: $('#defaultForm-email1').val(),
password: $('#defaultForm-pass1').val()
}, success:function(response) {
$('#messageId').text("Login Successful");
},error: function () {
$('#messageId').text("Login Failed");
}
});
});
});
So if the login are incorrect you should be getting 403 forbidden status from the login api call and that would call the error callback.
Moreover, it's not a good approach to give errors on 200 success status. So the backend developer must update it to the appropriate statuses.
Thanks.
I need to validate, on server side, if a person with a given registration number is already on the database. If this person is already registered, then I proceed with the program flow normally. But, if the number is not already registered, then I'd like to show a confirmation dialog asking if the operator wants to register a new person with the number entered and, if the operator answers yes, then the person will be registered with the number informed on the form on it's submission.
I've tried
Server side(PHP):
if (!$exists_person) {
$resp['success'] = false;
$resp['msg'] = 'Do you want to register a new person?';
echo json_encode($resp);
}
Client side:
function submit(){
var data = $('#myForm').serialize();
$.ajax({
type: 'POST'
,dataType: 'json'
,url: 'myPHP.php'
,async: 'true'
,data: data
,error: function(response){
alert('response');
}
});
return false;
}
I can't even see the alert, that's where I wanted to put my confirmation dialog, with the message written on server side. Other problem, how do I resubmit the entire form appended with the operator's answer, so the server can check if the answer was yes to register this new person?
EDIT
I was able to solve the problem this way:
Server side(PHP):
$person = find($_POST['regNo']);
if ($_POST['register_new'] === 'false' && !$person) {
$resp['exists'] = false;
$resp['msg'] = 'Do you want to register a new person?';
die(json_encode($resp)); //send response to AJAX request on the client side
} else if ($_POST['register_new'] === 'true' && !$person) {
//register new person
$person = find($_POST['regNo']);
}
if($person){
//proceed normal program flow
}
Client side:
function submit(e) {
e.preventDefault();
var data = $('#myForm').serialize();
var ajax1 = $.ajax({
type: 'POST'
, dataType: 'json'
, async: 'true'
, url: 'myPHP.php'
, data: data
, success: function (response) {
if (!response.exists && confirm(response.msg)) {
document.getElementById('register_new').value = 'true'; //hidden input
dados = $('#myForm').serialize(); //reserialize with new data
var ajax2 = $.ajax({
type: 'POST'
, dataType: 'json'
, async: 'true'
, url: 'myPHP.php'
, data: data
, success: function () {
document.getElementById('register_new').value = 'false';
$('#myForm').unbind('submit').submit();
}
});
} else if (response.success) {
alert(response.msg);
$('#myForm').unbind('submit').submit();
}
}
});
}
There doesn't appear to be anything wrong with your PHP.
The problem is (1) You are doing the alert inside of an error callback, and your request isn't failing, so you don't see the alert. (2) You are alerting the string 'response' instead of the variable response.
It is also worth noting that you should be using the .done() and .fail() promise methods (http://api.jquery.com/jquery.ajax/#jqXHR).
Here is the fixed JS:
function submit() {
var data = $('#myForm').serialize();
// Same as before, with the error callback removed
var myAjaxRequest = $.ajax({
type: 'POST',
dataType: 'json',
url: 'myPHP.php',
async: 'true',
data: data
});
// The request was successful (200)
myAjaxRequest.done(function(data, textStatus, jqXHR) {
// The data variable will contain your JSON from the server
console.log(data);
// Use a confirmation dialog to ask the user your question
// sent from the server
if (confirm(data.msg)) {
// Perform another AJAX request
}
});
// The request failed (40X)
myAjaxRequest.fail(function(jqXHR, textStatus, errorThrown) {
console.log(errorThrown);
});
return false;
}
Also, you are setting a 'status' in PHP and checking that in the JS (I presume). What you want to be doing is setting a HTTP status code from the server, as below:
if (!$exists_person)
{
$resp['msg'] = 'Do you want to register a new person?';
// 400 - Bad Request
http_response_code(400);
echo json_enconde($resp);
}
Then, jQuery will determine whether the request failed based on the status code you respond with. 200 is a successful request, and 400 numbers are fail.
Check out this page for a full list: https://httpstatuses.com/
Okay so this is a two part question; I'll try my best to answer both parts:
Part 1: How to detect if success is false and trigger the confirmation popup?
In jQuery.ajax the error handler is triggered based on response code. This is probably not what you want. You can use your success handler and test the value res.success to see if it's true or false. It would be something along the lines of:
function submit(e) {
e.preventDefault();
var data = $('#myForm').serialize();
$.ajax({
type: 'POST',
dataType: 'json',
url: 'myPHP.php',
async: 'true',
data: data
}).done(function(res) {
if (!res.success) {
alert(res.msg);
}
});
}
Part 2: How do I resubmit with a confirmation?
Working off of our previous code we will make some changes that allow for submit() to be passed an argument registerNew. If registerNew is true we will pass it as a param to the ajax handler in the PHP so it knows we want to register a new person. The Javascript will look something like this:
function submit(e, registerNew) {
if (e) e.preventDefault();
var data = $('#myForm').serialize();
var ajax_options = {
type: 'POST',
dataType: 'json',
url: 'myPHP.php',
async: 'true',
data: data
};
ajax_options.data.register_new = !!registerNew;
$.ajax(ajax_options).done(function(res) {
if (!res.success && confirm(res.msg)) {
submit(null, true);
}
});
}
As you can see here, we are passing a new register_new param in the data in our ajax options. Now we need to detect this on the PHP side, which is easy enough and looks like this (this goes in your php ajax handler):
if ($_POST["register_new"]) {
// new user registration code goes here
} else {
// your existing ajax handler code
}
Add confirm inside submit function
function submit(){
var data = $('#myForm').serialize();
if (confirm('Are you ready?')) {
$.ajax({
type: 'POST'
,dataType: 'json'
,url: 'myPHP.php'
,async: 'true'
,data: data
,error: function(response){
alert('response');
}
});
}
return false;
}
I have a problem. My jquery submit function, tries to do a GET request, while I set it up as a POST request.
my submit function
function authenticate() {
var form = $('#form-login');
form.submit(function(evt) {
evt.preventDefault();
console.log('submitting!');
console.log(form.serialize());
$.ajax({
type: 'POST',
url: 'http://website.dev/loginz',
data: form.serialize(),
dataType: 'json',
success: function(data) { log_error(data.error); }
});
});
}
routes.php
Route::post('loginz', 'User\LoginController#authenticate');
What my chrome browser says
GET http://website.dev/loginz/ 405 (Method Not Allowed)
/Loginz
/* POST */
function authenticate(Request $request) {
$username = $request->input('username');
$password = $request->input('password');
if(Auth::attempt(['username' => $username, 'password' => $password])) {
redirect()->route('home'); /* should redirect to player */
}
return response()->json(['error' => trans('errors.user_password_combination').' => '.$username.' & '.$password]);
}
Maybe I am just stupid and hit a wall, I have stared myself to death and I just can't see the error :P
What version of laravel are you using?
Remind csrf token must be given for post requests.
you can disable the csrf verification also in \App\Http\Middleware\VerifyCsrfToken::class,
But would be better if you set in on the client side.
Meaning from laravel you should in the blade template add something like:
$( document ).ready(function() {
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' } });
});
But first, in Chrome (example) inspector -> network -> header: what is the request method?
The fault was an 301 redirect. The problem was created by myself. I added a redirect from non slash to slash (ex. /page to /page/) so the POST was redirected to a GET request.
I wrote a JQuery script to do a user login POST (tried to do what I have done with C# in the additional information section, see below).
After firing a POST with the JQuery code from my html page, I found the following problems:
1 - I debugged into the server side code, and I know that the POST is received by the server (in ValidateClientAuthentication() function, but not in GrantResourceOwnerCredentials() function).
2 - Also, on the server side, I could not find any sign of the username and password, that should have been posted with postdata. Whereas, with the user-side C# code, when I debugged into the server-side C# code, I could see those values in the context variable. I think, this is the whole source of problems.
3 - The JQuery code calls function getFail().
? - I would like to know, what is this JQuery code doing differently than the C# user side code below, and how do I fix it, so they do the same job?
(My guess: is that JSON.stringify and FormURLEncodedContent do something different)
JQuery/Javascript code:
function logIn() {
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
success: getSuccess,
error: getFail
});
} catch (e) {
alert('Error in logIn');
alert(e);
}
function getSuccess(data, textStatus, jqXHR) {
alert('getSuccess in logIn');
alert(data.Response);
};
function getFail(jqXHR, textStatus, errorThrown) {
alert('getFail in logIn');
alert(jqXHR.status); // prints 0
alert(textStatus); // prints error
alert(errorThrown); // prints empty
};
};
Server-side handling POST (C#):
public override async Task ValidateClientAuthentication(
OAuthValidateClientAuthenticationContext context)
{
// after this line, GrantResourceOwnerCredentials should be called, but it is not.
await Task.FromResult(context.Validated());
}
public override async Task GrantResourceOwnerCredentials(
OAuthGrantResourceOwnerCredentialsContext context)
{
var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
var user = await manager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError(
"invalid_grant", "The user name or password is incorrect.");
context.Rejected();
return;
}
// Add claims associated with this user to the ClaimsIdentity object:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
foreach (var userClaim in user.Claims)
{
identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
}
context.Validated(identity);
}
Additional information: In a C# client-side test application for my C# Owin web server, I have the following code to do the POST (works correctly):
User-side POST (C#):
//...
HttpResponseMessage response;
var pairs = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>( "grant_type", "password"),
new KeyValuePair<string, string>( "username", userName ),
new KeyValuePair<string, string> ( "password", password )
};
var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
{
var tokenEndpoint = new Uri(new Uri(_hostUri), "Token"); //_hostUri = http://localhost:8080/Token
response = await client.PostAsync(tokenEndpoint, content);
}
//...
Unfortunately, dataType controls what jQuery expects the returned data to be, not what data is. To set the content type of the request data (data), you use contentType: "json" instead. (More in the documentation.)
var postdata = JSON.stringify(
{
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
});
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: postdata,
dataType: "json",
contentType: "json", // <=== Added
success: getSuccess,
error: getFail
});
If you weren't trying to send JSON, but instead wanted to send the usual URI-encoded form data, you wouldn't use JSON.stringify at all and would just give the object to jQuery's ajax directly; jQuery will then create the URI-encoded form.
try {
jQuery.ajax({
type: "POST",
url: "http://localhost:8080/Token",
cache: false,
data: {
"username": document.getElementById("username").value,
"password": document.getElementById("password").value
},
dataType: "json",
success: getSuccess,
error: getFail
});
// ...
To add to T.J.'s answer just a bit, another reason that sending JSON to the /token endpoint didn't work is simply that it does not support JSON.
Even if you set $.ajax's contentType option to application/json, like you would to send JSON data to MVC or Web API, /token won't accept that payload. It only supports form URLencoded pairs (e.g. username=dave&password=hunter2). $.ajax does that encoding for you automatically if you pass an object to its data option, like your postdata variable if it hadn't been JSON stringified.
Also, you must remember to include the grant_type=password parameter along with your request (as your PostAsync() code does). The /token endpoint will respond with an "invalid grant type" error otherwise, even if the username and password are actually correct.
You should use jquery's $.param to urlencode the data when sending the form data . AngularJs' $http method currently does not do this.
Like
var loginData = {
grant_type: 'password',
username: $scope.loginForm.email,
password: $scope.loginForm.password
};
$auth.submitLogin($.param(loginData))
.then(function (resp) {
alert("Login Success"); // handle success response
})
.catch(function (resp) {
alert("Login Failed"); // handle error response
});
Since angularjs 1.4 this is pretty trivial with the $httpParamSerializerJQLike:
.controller('myCtrl', function($http, $httpParamSerializerJQLike) {
$http({
method: 'POST',
url: baseUrl,
data: $httpParamSerializerJQLike({
"user":{
"email":"wahxxx#gmail.com",
"password":"123456"
}
}),
headers:
'Content-Type': 'application/x-www-form-urlencoded'
})
})
I am designing some PHP pages to process forms. In these pages I want to redirect if result is successful or print a message if there was an error. Structure of pages is like this:
$arg = $_POST["arg"];
if (isset($arg)) {
if (function($arg)) {
header ("Location: page2.php");
}
else {
echo "Response was not successfully";
}
}
else {
echo "$arg parameter was not defined";
}
When I need to print messages I use cftoast for JQuery (http://www.jqueryscript.net/other/Android-Style-jQuery-Toaster-Messages-Plugin-cftoaster.html)
To handle all forms I am using this Javascript function:
$(document).ready(function() {
$("#asynchronousForm").submit(function() {
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
success: function(data) {
$("body").cftoaster({content: data});
window.location.href = ""; //Refresh page to clear possible errors
}
})
return false;
});
My problem is, when form redirects, sometimes appears problems like no redirection and shows empty toast, refreshing page with duplicated input fields... How can I solve this problem? I am using JQueryMobile as skeleton of my webpage.
A good way to handle AJAX responses is to use JSON.
It will allow you to send multiples data and do a redirect or show message depending of AJAX result.
In PHP you can use json_encode() to convert and array to JSON.
$arg = $_POST["arg"];
if (isset($arg)) {
if (function($arg)) {
exit(json_encode(array('redirect' => 'page2.php')));
}
else {
exit(json_encode(array('message' => 'Response was not successfully')));
}
}
else {
exit(json_encode(array('message' => $arg.' parameter was not defined')));
}
AJAX:
You just have to add dataType: 'json'.
You can also use $.getJSON()
$.ajax({
type: $(this).attr('method'),
url: $(this).attr('action'),
data: $(this).serialize(),
dataType: 'json',
success: function(json) {
if ( json.redirect )
window.location.href = json.redirect;
else
$("body").cftoaster({content: json.message});
}
})