In my backend I authenticate user once inlogging and then store the authenticated sessions at the server. Then after each user's request i check if the session associated with a request is stored as authenticated. The problem is that when I use JavaScript requests a new HTTP session is used each time i send something to my server written in Java.
When I use Postman everything is okay because it stores session through many requests.
//Here is authentication on server side - it works fine
#CrossOrigin
#RequestMapping(value= "/login", method = RequestMethod.POST)
public #ResponseBody String login(#RequestBody Account retrievedAccount,
HttpServletRequest httpServletRequest) {
if (retrievedAccount != null) {
Account account =
accountDAO.getAccountByLogin(retrievedAccount.getLogin());
if (account != null &&
account.getPassword().equals(retrievedAccount.getPassword())) {
this.registeredSessionsContainer.add(httpServletRequest.getSession());
return new ResponseEntity(HttpStatus.OK).toString();
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED).toString();
}
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED).toString();
}
}
Here is a simple way to check if a session is already authenticated:
#CrossOrigin
#RequestMapping(value= "/checkLogon", method = RequestMethod.GET)
public #ResponseBody String checkLogon(HttpServletRequest
httpServletRequest) {
if(this.registeredSessionsContainer.
contains(httpServletRequest.getSession()))
return new ResponseEntity(HttpStatus.OK).toString();
} else {
return new ResponseEntity(HttpStatus.UNAUTHORIZED).toString();
}
Here is how i login to service in my frontend JavaScript:
performLoggingToService(){
var login = document.getElementById("loginField").value;
var password = document.getElementById("passwordField").value;
var url = "http://localhost:8080/mvc1/login";
var method = "POST";
var crendentialsObject = { "login": login, "password": password };
var crendentialsObjectJSON = JSON.stringify(crendentialsObject);
console.log(crendentialsObjectJSON);
var req = new XMLHttpRequest();
req.open("POST", url, true);
req.setRequestHeader("Content-Type", "application/json");
req.send(crendentialsObjectJSON);
//console.log("Is this undefined: "+(loginComponent==undefined));
var props = this.props;
var thisObjectPointer = this;
req.onload = function (e,thisObject=thisObjectPointer) {
var status = req.status; // HTTP response status, e.g., 200 for "200 OK"
var data = req.responseText; // Returned data
if(data.includes("200 OK")){
console.log("Checking LOGON STATE METHOD#2: ");
thisObject.props.refreshLogonStateInMainBand(login);
} else {
// inform user about wrong credentials
}
}
}
An then when i perform check if i am already logged in one address /checkLogon I use:
checkLogonState(currentUserName) {
console.log("CheckLogonState CALLED!");
var url = "http://localhost:8080/mvc1/checkLogon";
var method = "GET";
var req = new XMLHttpRequest();
var loginData;
req.overrideMimeType("application/json");
req.open('GET', url, true);
req.onload = function() {
}
req.send();
req.onreadystatechange=(e)=>{
if(req.readyState === 4 && req.responseText.length>0) {
if(req.responseText.includes("200 OK")){
console.log("Authenticated!!!");
this.changeMainComponentStateToLogin();
this.currentUserName = currentUserName;
this.oneTimeLogonCheckAction=false;
} else {
console.log("Not logged in!!!")
this.changeMainComponentStateToIdle();
this.currentUserName=undefined;
this.oneTimeLogonCheckAction=true;
}
this.forceUpdate();
}
}
}
As you may expect responseTest includes 404 Unauthorized not 200 OK.
I tried it on InternetExplorer, Microsoft Edge and Chrome. None of them reuses session.
After each of my requests console on server side shows that the requests are sent from other sessions - each request in a new session.
I would like to get to know how can I use same session if i use one the same browser window through many requests.
Set withCredentials to true for all XMLHttpRequest,
var req = new XMLHttpRequest();
req.withCredentials = true;
req.open("POST", url, true);
req.setRequestHeader("Content-Type", "application/json");
req.send(crendentialsObjectJSON);
will help to persist the session across calls.
At server side add this to all your controllers to solve cors issues,
#CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")
Related
We have a server which is implemented by python flask and it's RESTful. Since it is RESTful, we must develop the front-end pages using APIs.
The problem is, our server uses flask's built-in Login_manager and session modules to manage client sessions. When I try to send requests to #login-required APIs, the server won't allow me. Based on my searches, I have to somehow send front-end's session cookie to the server, along with my requests. So how should I do this (If this is the solution)? And what should I add to my javascript login and API fetch codes?
JS login :
var request = new XMLHttpRequest();
var url = 'http://127.0.0.1:5000/api/login';
var user = {
'email': email,
'password': password
};
request.open('POST', url, true);
request.setRequestHeader("Content-Type", "application/json");
request.onload = function() {
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
var resp = JSON.parse(this.response);
if (resp.status === "OK") {
sessionStorage.setItem('user', JSON.stringify(resp.user));
document.cookie = "user_id="+resp.user.id;
window.location.replace('app.html');
} else {
alert("User info not correct");
}
} else {
alert("Request not made");
}
}
request.send(JSON.stringify(user));
And then, script isn't working because the /showApps API is #login-required :
var request = new XMLHttpRequest();
var url = 'http://127.0.0.1:5000/api/showApps';
request.open('GET', url, true);
request.onload = function(e) {
//manage data
}
request.send();
I am getting the raw data of the drafted from Gmail API "get" method and sending it using Gmail API "send" method.
'var url = 'https://www.googleapis.com/gmail/v1/users/me/messages/id?
format=raw&alt=json&access_token=' + token;
url = url.replace("id", emailId);
var x = new XMLHttpRequest();
x.open('GET', url , true);
x.send();
x.onload = function() {
var jsonRes = JSON.parse(x.response);
sendEmail(jsonRes.raw);
}
function sendEmail(raw) {
if (raw) {
var request = new XMLHttpRequest();
var url = 'https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json&access_token=' + token;
params = "raw=" + raw;
request.open('POST', url , true);
request.setRequestHeader("Authorization", "Bearer " + token);
request.setRequestHeader("Content-type", "application/json");
request.send(params);
request.onload = function() {
if (200 === request.status) {
alert("Email sent successfully");
}
}
}`
I am getting 401 status.
If I am sending this raw data from API page itself, then it is sent successfully. Therefore the raw data is correct.
I am missing something while sending the email. Please help!
A 401 error means "invalid credentials", most likely because your token has expired or isn't valid.
The Google API explorer and Google Javascript libraries take care of the token for you (generally), but if you're calling the service endpoints directly with XMLHttpRequest(), you'll have to manage the token yourself.
If you want to go that route, here are the details you have to implement: https://developers.google.com/identity/protocols/OAuth2
You can try things out in the "Oauth2 playground": https://developers.google.com/oauthplayground/
Thank you for all responses.
I sent the email using the following code-
function sendEmail(raw) {
if (raw) {
var request = new XMLHttpRequest();
var url = 'https://www.googleapis.com/gmail/v1/users/me/messages/send';
var params = JSON.stringify({'raw': raw});
request.open('POST', url , true);
request.setRequestHeader("Authorization", "Bearer " + token);
request.setRequestHeader("Content-type", "application/json");
request.send(params);
request.onload = function() {
if (200 === request.status) {
alert("Email sent successfully");
}
}
}
}
There were two mistakes I rectified-
1. The token was sent in URL as well as header. It should be sent only in header.
2. The param raw was sent as String but it should be sent as a JSON object.
For the past 5 hours I've been trying to get JSON data from an API that requires login using .net C#.
Every combination I try results in "error 401 - unauthorized".
I have a working example in Javascript, maybe this would help.
function signin(){
username = $('#inputUsername').val();
pass = $('#inputPassword').val();
if(pass.length > 0 && username.length > 0){
//Build post request
$.post( source+"/login", {username: username, password:pass}, function( data, textStatus, jqxhr ) {
$("header div h4#header_username").html(username);
token = data.auth;
$('#main-content').show()
$('#form-signin').hide()
populateVehicles();
});
}
}
On c# I've tried many code combinations including:
NetworkCredential netCredential = new NetworkCredential("USERNAME", "PASSWORD");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Credentials = netCredential;
request.Method = "POST";
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes("USERNAME" + ":" + "PASSWORD"));
//request.PreAuthenticate = false;
//request.Proxy.Credentials = CredentialCache.DefaultCredentials;
//request.UseDefaultCredentials = true;
//string base64Credentials = GetEncodedCredentials();
//request.Headers.Add("Authorization", "Basic " + base64Credentials);
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8);
return reader.ReadToEnd();
}
}
catch (WebException ex)
{
WebResponse errorResponse = ex.Response;
using (Stream responseStream = errorResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.GetEncoding("utf-8"));
String errorText = reader.ReadToEnd();
// log errorText
}
throw;
}
}
Some of the code has "//" because I've tried various variations.
I'm clueless.
Thanks in advance!
Using doetnet core 2.1, here's a basic example. I checked jquery docs and I think your js example sends form encoded data. You can easily check that in your browsers developer tools > network tab.
Form Encoded
using (var client = new HttpClient())
{
var response = await client.PostAsync("https://myaddress.com/path", new FormUrlEncodedContent(new Dictionary<string, string>()
{
{ "username", "user" },
{ "password", "mypass" }
}));
if (response.StatusCode == HttpStatusCode.OK)
{
var responseString = await response.Content.ReadAsStringAsync();
// do something
}
}
"form url encoded" means, it will generate a request that looks like this:
say=Hi&to=Mom
with header Content-Type: application/x-www-form-urlencoded
s.a. https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
Json Content
using (var client = new HttpClient())
{
var response = await client.PostAsync("https://myaddress.com/path", new StringContent(JsonConvert.SerializeObject(new
{
username = "user",
password = "password"
}), Encoding.UTF8, "application/json"));
if (response.StatusCode == HttpStatusCode.OK)
{
var responseString = await response.Content.ReadAsStringAsync();
// do something
}
}
"json" means, it will generate a request, that looks like this
{ "say": "Hi", "to": "Mom" }
with header Content-Type: application/json
Note that HttpClient is thread safe and you should prefer a single instance if you do multiple requests.
If your're on dotnet core the following article will help you getting started with HttpClient: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.1
See https://stackoverflow.com/a/4015346/2085502 mentioned by #Archer to get an overview over different http client libs in c#.
To troubleshot if your backend working properly, check it by try sumbit the form with real usename and password and wrong email/password by clicking inside the . username and password must be inside the form too. Also in your form must be have action="" attribute with value of login url.
Try to set up, if login success some word. example, simply print 'success'
Then if failed, print another message. example 'failed', 'wrong password', 'email not exist' aor etc.
So after that. use this Javascript code.
function signin(){
var formData = new FormData();
formData.append('userame', document.getElementById('inputUsername').value);
formData.append('password', document.getElementById('inputPassword').value);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://www.yoursite.com/login-url-here', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4){
var data = xhr.responseText;
if(data){
if(data == 'success'){
// yes your login page return success, do something below
document.getElementById('main-content').style.display = 'block';
document.getElementById('form-signin').style.display = 'none';
populateVehicles();
alert('login success')
} else {
alert('ops, failed to login, the page print this messages '+ data)
}
} else {
alert('ops your login page not print anything')
}
}
}
xhr.send(formData);
}
I am having some trouble getting an access token from a site for a web application. The response to the following is
"{"error":"invalid_request","error_description":"The grant type was not specified in the request"}".
I have specified the grant type below but it seems I have not formatted the request correctly.
Any suggestions?
var getToken = new XMLHttpRequest();
getToken.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML =
this.responseText;
}
};
getToken.open("POST", "https://api2.libcal.com/1.1/oauth/token", true);
getToken.send('grant_type=client_credentials','client_id=XXX', 'client_secret=XXXXXXXXXXXXXXXXXXXX');
As you are doing a Post Request to get an access token , the parameters should be send in the body (JSON) like below : (I tested ,it works fine )
// form data for the post request
var data = {
"grant_type":"client_credentials",
"client_id": "XXX",
"client_secret": "XXXXXXXXXXXXXXXXXXXX"
};
// construct an HTTP request
var getToken= new XMLHttpRequest();
getToken.open("POST", "https://api2.libcal.com/1.1/oauth/token", true);
getToken.setRequestHeader('Content-Type', 'application/json');
// send the collected data as JSON
getToken.send(JSON.stringify(data));
I am trying to send data to node via a XMLhttprequest. The data looks like this (/q/zmw:95632.1.99999.json). My connection to Node is correct, however, I was getting an empty object so I set the headers to Content-Type application/json and then stringified the data. However Node gives me a Unexpected token " error. I presume it is because of the string, however, if I don't stringify the data then it errors out because of the "/" in the data. How do i properly send the data using pure Javascript. I want to stay away from axios and jquery because I want to become more proficient in vanilla javascript. I will make the final call to the api in node by assembling the url prefix and suffix.
Here is my code:
function getCityForecast(e){
//User selects option data from an early JSONP request.
var id = document.getElementById('cities');
var getValue = id.options[id.selectedIndex].value;
//Assembles the suffix for http request that I will do in Node.
var suffix = getValue + ".json";
var string = JSON.stringify(suffix);
console.log(suffix);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(string);
}
Node.js code:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
var request = require('request');
var http = require('http');
// ****************** Middle Ware *******************
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/public'));
app.post('/', function(req, res){
console.log('working');
console.log(req.body);
});
app.listen(3000, function() { console.log('listening')});
I figured it out my mistake and this was my problem. I was trying to send a string instead of an object. So it wasn't proper JSON like this:
var string = JSON.stringify(suffix);
To remedy the situation I added:
var newObj = JSON.stringify({link : suffix});
This allowed my post to be successful because I was now sending an object hence the word Javascript Object Notation.
This is working for me, at the moment. The REST API I'm hitting requires a token. Yours might not, or it might be looking for some other custom header. Read the API's documentation. Note, you might need a polyfill/shim for cross browser-ness (promises). I'm doing GET, but this works for POST, too. You may need to pass an object. If you're passing credentials to get a token, don't forget window.btoa. Call it like:
httpReq('GET', device.address, path, device.token).then(function(data) {
//console.log(data);
updateInstrument(deviceId,path,data);
}, function(status) {
console.log(status);
});
function httpReq(method, host, path, token) {
if(method === "DELETE" || method === "GET"|| method === "POST" || method === "PUT" ){
var address = 'https://' + host + path;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, address, true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader ("X-auth-token", token);
//xhr.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
xhr.onload = function() {
var status = xhr.status;
if (status == 200 || status == 201 || status == 202) {
resolve(xhr.response);
}
// this is where we catch 404s and alert what guage or resource failed to respond
else {
reject(status);
}
};
xhr.send();
});
} else {
console.log('invalid method');
}
};