I'm working on a website for school, using Dialogflow, ReactJs and NodeJs. I am pretty new to doing this and I am not certain whether my implementation will work for my use case.
My website involves a game, which the server-side needs game state information from. I am sending requests from React to NodeJs as follows:
axios({
method: 'post',
url: '/game_state',
data: {'current_player': current_player}
// ... (more data is sent in reality)
}
);
My post requests are then handled by NodeJs as follows:
app.post('/game_state',express.json(),(event)=>{
current_player = event.body.current_player;
// ... (more data)
});
This data can then be accessed by a Dialogflow request. For example, if the user asks: "Who's turn is it?", an intent with webhook fulfillment can then be triggered. The code for that:
function turn(agent){
current_player == 1 ? agent.add("Your turn") : agent.add("My turn");
}
As I said before, I am not very experienced with developing websites. I want to be able to use my implementation with multiple users at the same time, so one user's game states shouldn't influence those of another user.
So far, I've been using (the free version of) ngrok to test my website. My implementation works perfectly fine if only one user is accessing the link. However, when I open the website twice on the same computer (using the ngrok-generated link) and interact with e.g. the turn intent, I notice that the turn response will be the same for both even if for one session, it's the player's turn and for the other, it's the chatbot's turn.
Most likely, the post request is being overwritten given that the same link is used. I would like to find a solution that makes it possible to use the same link but have the server keep the game state information separate for each user. I feel like this might be possible with a user ID, but I'm stumped on how to implement that.
I know something like this may be an option: app.get("/game_state/:id", ...), but I am not sure how to also get this information to be available for the Dialogflow part of the implementation. Dialogflow calls the server itself, so it doesn't pass this user ID with it. Somehow, I'd need to distinguish it there as well.
Any suggestions would be greatly appreciated!
When you make Dialogflow detected intent API call at that time you are creating a session path
const sessionPath = await sessionClient.projectAgentSessionPath(PROJECTID, sessionId);
If you pass session Id = 123456789A so for this Id Dialogflow managed all context and parameter on Id 123456789A
session Id = USER
when you get the webhook call to the server you also get this session Id or we also called UserId like
let userId = agent.session.split('/')[4]
you can find more information here
dialogflow session
Related
For simplicity assume that I have entity user and in my frontend side (react) I am making an Axios get request to get all users to display them.
In the componentDidMount I am doing a get request const res = axios.get(myurl) then map the res to be displayed.
However, if a new user is entered in the database I have to refresh the page to see the update.
Here is my question, how to make the get request to be like running or something like this so if any changes happens in the database it reflects the get request.
You can use the useEffect in react
import React,{useEffect}from 'react'
function getAllUsers(){
//your code here...
}
useEffect(()=>{
getAllUsers();
})
This is a real-time updates, and we have multiple practices for such a case.
Before reading the answer, you need to know that this case is about the real-time updates concept and not a problem with a line of code solution. You need to implement real-time system in your app to achieve what you want.
1st Practice
Is to use a real-time library like Socket.io, so that you can listen to the events you want.
You can find here an example for Node.JS with React.JS
2nd Practice
Is to use a database that provides real-time updates like Firebase. Here you can find an example.
Quick background
I am building an API with Node.js, Express and Mongoose. The authentication I implemented works with the passport-headerapikey package. I search the DB for the user with the api-key and add that user to the req Object. Thus ensuring my knowledge about the identity the whole time until the request ends.
Authorization
Let's get to the issue.
Up until now I called an authorize() function in every endpoint manually before doing anything. Like so:
router.post('/', (req, res) => {
autorize('admin', req.user.role) // method is called at every route manually
.then(() => {
... do stuff here
})
.catch(err => req.status(403).send())
}
My colleague said to me it is not a good solution and, rather than just securing the endpoint itself, I should have a session management that makes the current user available globally so that I can authorize at any point in every function individually.
Meaning:
A Method createUser(obj) could then call inside itself an authorization method or check for a condition like so:
createUser(obj) {
if (currentUser.role !== 'admin') {
return false
}
obj = new User(obj)
return obj.save()
}
That would mean I would return false in every function if a condition is met. Accessing the globally available currentUser for that session. (e.g. globalCurrentUser.role !== admin or something along those lines)
My question(s)
Is it bad practice to just secure endpoints and not functions?
Can't I just require an extra param "auth" with every function, so that when called it needs to receive the currentUser.role like in my authorize() function or it returns false? That means I pass the user manually to every function or it will simply fail
If I should have a session management for global access of the user during the request: Do you have suggestions for frameworks?
Thanks in advance,
Benno
Authentication and authorisation are two different things and should be treated separately. Authentication says "who are you?" and authorisation says "do you have permission?". Baring in mind that Express is designed entirely around middleware, I would do the following.
Abstract your authentication into a single piece of middleware which runs for all your endpoints using app.use() before you mount your router / routes.
Create an authorisation function which can be called from anywhere, it takes a user (or id or whatever you have) and a role, and it then checks if the user has that role.
Think of it like this, your authorisation will never change, it is core to your application. If you decided to ditch Expressjs and use Koa or move from traditional HTTP requests to Web Sockets you wouldn't want to change your authorisation logic. But your authentication may well change, you may wish to no longer use a header to store the token, perhaps you switch to cookies or something else entirely, you may wish to change this.
You'll end up with a piece of global middlware which checks an auth token and attaches the user object to the req. Then you'll have a utility function called something like userHasRole which will be called at any endpoint which requires a specific role within the application. You're then free to check permissions at any point in the application. This may be in very different places across your application, for instance you might check if they're an admin at the beginning of a request to some admin dashboard, but you might check permissions later on if they try to access a particular resource. When accessing a particular resource you might want to let them through and determine at the last minute if they have access to the resource. (It's hard to give a specific example without knowing more about your application).
In some instances it might be suitable to check at the beginning of the business logic, in other places it might make sense to check later on. This shouldn't matter, you should be able to run this check whenever you need to. This will depend entirely on the business logic and placing it in every single function ever may be useless if it's just formatting a string output, but it might be useful when trying to pull out a DB record.
Is there a way that I can get the API.ai agent information from the fulfillment request?
I am trying to capture any unique parameter from Node.js code that can be passed from Agent. This will be utilized for proceeding with the logic for multiple agents using a single code base.
For Amazon Alexa I could get the Skill Application Id from the session. Is there something similar in API.ai?
If you want to get agent id you can make something like this (using express framework):
app.post(`/:agent_id/webhook`, (req, res) => {
const apiai_agent_id = req.params.agent_id;
// webhook code...
});
And on fulfillment page in this case for each agent you have to specify it's own webhook URL like
https://mywebhooks.com/55982e7c-db17-47ee-92bb-176476228942/webhook
(you can get agent id for webhook URL from browser's address bar)
You can use the API.AI's sessionId or intentId which will be unique across agents. The sessionId and intentId* is sent with every fulfillment webhook request. The of the JSON sent are similar to this:
{
"id": "1a4b6209-51ec-47a1-a797-2e2f71926ac8",
"sessionId": "1503343146047"
...
}
but will contain other elements as well.
*intentId may include additional numeric identifier after the intent ID if you are using slot filling
Source: https://api.ai/docs/fulfillment#request
I am still new to Node and Express, and I've tried Googling this but perhaps I just need to know what to Google.
A big part of my app involves letting users create their own profile, which comes from a simple form submission. How would I go about taking what they've submitted in a form and putting that on a live page of my site?
Is there a middleware that I should be using for that? Is there a term I should Google? I just need to know how to get started and then I can figure the rest out from there. Thanks in advance for any suggestions.
Nicest way to do this is to set up a route with parameter. That way if user goes to /user/Jake he will see his profile. Like this: https://nimble-beetle.hyperdev.space/user/Jake
Check it out here: https://hyperdev.com/#!/project/nimble-beetle
app.get("/user/:username", function (request, response) {
response.send('thank you for registering, ' + request.params.username);
});
All you need to do is grab the username, fetch user's data and display his profile.
you are probably looking for the body-parser Middleware:
https://github.com/expressjs/body-parser
This one is decoding content of your request, it can decode Form data and JSON, depending how you send the data in your request, and gives you a JSON object.
I am building an HTTP server in nodeJS (homework assignment), and I need to manage HTTP sessions with cookies - for each session I send a cookie with UUID (string ID) and then when I get it back I reset the session's timer.
My question: should I open a session for each request (i.e. even an image/css request for example) or for each page?
This is my code now:
socket.on('data',function(data) {
//some code
// if no UUID exsit in request, create one for it
var request = new REQUEST.Request(data, resourceMap, rootFolder); //
//response will send the UUID created/sent in request
var response = new RESPONSE.Response(socket,request);
session(request); // look for uuid from request in data base
}
Right now when I load a page, the html request is always the first and a new UUID is created for it, but not for the next requests (images etc) in that page.
Also, when I hit a link to another page no UUID is created.
Any ideas why? Where is the best place to check for an existing UUID and add one if its not there? thanks!
You should create a session for one session. :) Not each request.
In the session you can set an UUID.
There are plenty of resources out there to help you. If your professor has allowed you to use libraries, I'd highly suggest checking your options. This is just a few: https://github.com/joyent/node/wiki/modules
Because it's homework question, I think it's best that you only get some direction to the 'answer'
Good luck