I have an app which uses Flask as a server, I use JavaScript in front-end and Python in back-end (flask). I have a problem with sending data using REST API from flask into JS.
The issue is that the users are receiving another users data. Here's hypothetical situation:
user A starts a new browser session and when he clicks he receives users A data (everything is OK at this point),
user B starts a new browser session and when he clicks he receives users B data (everything is OK at this point as well),
user A refreshes a browser and when he clicks he receives users B data and that is the problem
As you can see everything is working correctly but only if the user starts a new browser session. When the user refreshes the browser it all goes wrong.
The app has a few hundred lines of code so let me show you the most important part of the code.
Here is my simplified JS code:
document.getElementById('geolocate').addEventListener('click', event => {
const option ={
method: 'GET',
headers: {
'content-type': 'text/plain',
'cache-control': 'no-cache',
'cache': "no-store"
}
}
fetch('myUrl/api/v1/myEndpoint', option)
.then((response) => {
return response.text();
});
});
As you can see, it is just a simple event with fetch which is a receiver of POSTed data from backend.
Here you can see Flask code:
#app.route('myUrl/api/v1/myEndpoint', methods=['GET', 'POST', 'OPTIONS'])
def db_cords():
with open('/var/www/html/test.txt', 'r') as our_file:
for line in our_file:
return line
It reads the first line of our /var/www/html/test.txt file and sends it to the endpoint.
Here you can see the configuration of Flask:
app = Flask(__name__)
app.debug = False
app._static_folder = os.path.abspath("templates/static/")
config = {
"DEBUG": True, # some Flask specific configs
"CACHE_TYPE": "SimpleCache", # Flask-Caching related configs
"CACHE_DEFAULT_TIMEOUT": 10
}
# tell Flask to use the above defined config
app.config.from_mapping(config)
if __name__ == '__main__':
log = logging.getLogger('werkzeug')
log.disabled = True
app.run(host, port, debug, ssl_context=context)
I tried to add no-cache and simple-cache flags in headers but it did not help. Also I tried to use a decorator #after_request.
Everything in the app is working just fine. The only problem I have is the browsing session. Do you guys have any idea how to solve my issue?
Related
I am building a back-office app that requires users to sign in.
I have 2 external APIs:
API A : to manage user accounts and sessions
API B : to perform CRUD actions on another database (unrelated to users database)
The problem is that I don't want users to be able to perform calls to API B if their session is not valid. So I added some API endpoints in Next (under pages/api) that do the following actions:
verifying the validity of the session against API A
if session is valid: continue to step 3, if not: redirect to page /login
make the call to API B
Everything works fine if the session is valid but it fails if the session is not valid.
I have tried
res.redirect(307, '/login').end()
and
res.writeHead(307, { Location: '/login' }).end()
but it didn't work. It fails even by specifying the whole path (http://localhost:3000/login). What I don't understand is that I am successfully redirected to my /login page if I make the request directly from the browser (GET http://localhost:3000/api/data). It doesn't work when I make the request with Axios inside a React component.
Any idea how I can fix this?
As #juliomalves and #yqlim explained, I had to make the redirect manually based on the response of the API.
Faced same problem solve using below code:
Api
res.status(200).json({ success: "success" }) //add at last of the api to give response
page
import Router from 'next/router'
let res = await fetch('api', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
if (res.status == 200) {
Router.push('/location')
}
Answer is correct as #Jules Grenier sayes,but provided an example
You do not need .end(). Have you tried res.redirect(307, '/login')?
In Next.js v12 and v13, the following works for me.
// /api/example.js
const handler = async function (req, res) {
// custom logic
if (failed)
return res.redirect(307, '/login')
}
export default handler;
The API request must be initiated by a <form>.
redirect will not work with <fetch>
I am trying to communicate with a 3rd party API. I wrote the API in python. I want to update the name column in the database from the Wix web page using a user form and text box. The database updates and all of the endpoints are responsive using postman to test. I think the problem resides in my JavaScript on the Wix end.
I modeled the JavaScript from the Wix example at:
https://support.wix.com/en/article/calling-server-side-code-from-the-front-end-with-web-modules
I have a back end module called placeOrder stored in orderplaced.jsw that should post the variable 'name' to the api.
import { fetch } from 'wix-fetch';
// wix-fetch is the API we provide to make https calls in the backend
export function placeOrder(name) {
return fetch("https://reliableeparts.pythonanywhere.com/user", {
method: 'post',
name: JSON.stringify({ name })
}).then(function (response) {
if (response.status >= 200 && response.status < 300){
console.log(JSON.stringify({ name }))
return response.text();}
console.log(Error(response.statusText))
return Error(response.statusText);}
);
}
The front end module waits for a button click and stores the text box in the name variable.
{
import {placeOrder} from 'backend/orderplaced.jsw';
export function button1_click(event, $w) {
placeOrder(
$w("#input1").value)
.then(function() {
console.log("Form submitted to backend.");
}
);
}
}
Output:
2
The code appears to be reaching the back end. I believe the problem is in my placeOrder function as I am not very familiar with JavaScript.
Your code seems legit. The problem is with the server. When I tried to send a POST request to that address I got a 500 Internal Server Error.
You may check this curl and test the service yourself:
curl -i -X POST -H "Content-Type:application/json" https://reliableeparts.pythonanywhere.com/user -d '{"name":"test123"}'
You are probably missing the correct object structure the server is expecting or missing proper headers to POST the server (or both...)
Make sure you're following the API this server allows
I am trying to develop a two-tier web application with MarkLogic-9 employing server side JavaScript and HTTP app servers. I have a simple page that prompts for username/password and sends a GET request via Ajax to the app server (application-level authentication).
My login.sjs script:
//generate object with field names from Request params
var params ={}; //JSON parsed URL parameters
var field_names = xdmp.getRequestFieldNames().toArray();
for(var fname_idx in field_names){
params[field_names[fname_idx]] = String(xdmp.quote(xdmp.getRequestField(String(field_names[fname_idx]))));
}
//get username and password from passed paramters
var username = params.username;
var password = params.password;
var ret = xdmp.login(username,password);
ret;
I have tested this and verified that it works by printing the xdmp.currentUser().
The login page then redirects to a home page that displays basic user info. My problem is that I cannot figure out how to preserve the current user's session after the client-side redirect to the homepage.
The app server has application-level authentication and a default user called Login-User, which is a custom user that has only the privileges necessary to log in (xdmp:login). The app server is hosted on localhost:8601. I have found that when I run login.sjs directly from the browser (i.e. typing localhost:8601/login.sjs?username=test_user&password=test_password), my browser gets a cookie with the sessionID. However, when I run the login.sjs via an Ajax GET request, my browser does not get any cookies. I don't know if this is the issue but I though it might be worth mentioning.
I am still a MarkLogic novice so I may be going about this the completely wrong way. Basically, how do I go about continuing a single user's session after redirecting to a new page? Do I use cookies to save the sessionID? Should I preserve the username and password in local storage and log in every time the website invokes a new .sjs file?
For completeness, here is the client side js I use to make the Ajax call to login. Pretty self-explanatory. The login.sjs file just returns true/false if the login was successful.
function createLoginEar(){
$("#login-button").click(function(event){
var un = $("#username").val();
var pw = $("#password").val();
if(un){
params.username = $("#username").val();
}
if(pw){
params.password = $("#password").val();
}
event.preventDefault(); //prevent form from clearing
console.log("input entered");
$.ajax({
type: "GET",
url: url,
data: params,
success: function(data){
if(data == "true"){
console.log("worked");
window.location.href = "homepage.html";
} else{
invalidLogin();
}
},
error: function(data){
invalidLogin();
}
})
})
}
The problem is that once the page redirects to homepage.html, there seems to be no memory of the user having logged in and when homepage.html calls any .sjs file, the user resets to the default which is "Login-User".
Thanks in advance.
I suggest you look at Chapter 15 of the security guide.
There is a sample of application level authentication using Custom Login Pages.
Lastly, the sample of IP-based login is not what you need, but shows you how to use xdmp.Login to switch users from the default application user.
I think that with all of that covered (not much to it really), you will be able to walk backthrough your setup and re-work it.
The issue was that my browser was not collecting cookies from the login because of issues that are over my head, but I found the answer in another post so this may be a duplicate.
Get and store cookie (from Set-Cookie) from an AJAX POST response.
I just had to include the following line in my ajax request:
xhrFields: { withCredentials: true },
Since this will throw an error if you have a wildcard in you Access-Control-Allow-Origin header, I also had to change this line:
xdmp.addResponseHeader('Access-Control-Allow-Origin', '*');
to this:
xdmp.addResponseHeader('Access-Control-Allow-Origin', 'http://localhost:8010');
And now my browser collects cookies.
When I try to login emodal.com (I assume it uses basic authentication because it just requires a user/pass) on the browser it works fine and lets me go to a certain page and lets me through. However when I try to go in the page that I want and authenticate programmatically (using request or request-promise) it gets denied because of "invalid credentials". It seems like I need to login manually through a browser or something by clicking the login button and THEN i would be able to go to the private protected page that I want (why doesn't it work programmatically whereas the browser (google chrome) works? Is it going through a second step in the authentication process that I am not aware of?)
Here I provided 3 screenshots of how the devtools console looks when I log in (it makes a request to ValidateWharfageUser, then Login, then GetStatus as shown, then I guess thats where it denies me programmatically).
import dotenv = require('dotenv');
dotenv.config({ path: '../logins.env' });
import rp = require('request-promise');
const jsonUrl = `http://availability.emodal.com/ImportAvailability/GetContainerInfoList?sgrdModel=%7B%22searchtext%22:%22%22,%22page%22:1,%22pageSize%22:280,%22sortBy%22:%221%22,%22sortDirection%22:%22asc%22,%22sortColumns%22:%22%22%7D`;
const authOpts = {
uri: jsonUrl,
auth: {
user: process.env.EMODAL_id,
pass: process.env.EMODAL_pw,
sendImmediately: false
},
method: 'get'
}
rp(authOpts)
.then(resp => {
console.log(resp);
}).catch(err => { throw Error(err)});
The 3 screenshots:
http://i.imgur.com/hjThLt1.png
http://i.imgur.com/0uPAMMs.png
http://i.imgur.com/xBF2DAV.png
This is for a class project. It has a jQuery mobile interface and a Python Google App Engine back end. One part of the requirement is to have user accounts.
One way to do this is with Google's built-in User type. I attempted this route first. I set up a $.get request to a handler on the App Engine. I simply wanted to console.log one message if the user was signed in, and a different one if they were not. If I logged in from my app engine page, it worked fine. If I did so from my web interface, it did not recognize the login.
So I switched to sessions using "from webapp2_extras import sessions". I did this:
`
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
#Get a session store for this request
self.session_store = sessions.get_store(request=self.request)
try:
#Dispatch the request
webapp2.RequestHandler.dispatch(self)
finally:
#Save all sessions
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
#Returns a session using the default cookie key
return self.session_store.get_session() `
and sent a get request to this:
class LogInHandler(BaseHandler):
def get(self):
self.response.headers.add_header("Access-Control-Allow-Origin", "*")
self.session['user'] = "dude"
self.response.write("just attempted to set session variable");
using this JS request:
function logIn() {
$.get('http://my_app.appspot.com/login', {username : "dude", password : "doesn't_matter"}, function(data, status) {
console.log(data);
});
}
I then send a get to this handler:
class ViewCollHandler(BaseHandler):
def get(self):
self.response.headers.add_header("Access-Control-Allow-Origin", "*")
user = self.session.get('user')
if user:
self.response.write("There is a user!")
else:
self.response.write("No user!")
Even if I first "login", I always get the response "No User!".
Again, this works fine if I access /login on my_app.appspot.com page. But if I send the get through my jQuery interface, it doesn't.
What am I doing wrong? Why does GAE recognize sessions and Google sign-ins from my_app.appspot.com, but not from http://my_ap.school.edu?