I'm sorry if this question is a bit vague, but I'm tackling this problem for the first time and any pointer would be useful.
I am building a web app using ReactJS and I need a login system - first page with two fields username / password and submit button. The server returns a token (1234) and this needs to be used in an auth header (Authorization: Bearer 1234) in order to access the protected area.
How should I handle the login and make the browser update itself with the new content available after login?
As the others have pointed out, it is a good idea to use React-Router.
I think you can use pattern like this: You get user inputs and send them via AJAX (with JQuery, Superagent, whatever you want). If the input is valid and user authenticated, the server sends back token with some user info, which can include his roles or permissions. Based on these received data, you can use React-Router to render other component, e.g. welcome page (by calling replaceState on React-Router history object - in flux action for example).
Additionally, you should save this token in a cookie or into a session/local storage (in order to be able to use it on every subsequent request), and the user info could be stored in a Flux store. After saving this user the store emits change event, which should lead to rerender of your root component with the user information you got.
Then, based on the new user roles or permissions in your store, you can have for example ES7 decorator on some of your components deciding, if it displays the actual component or not.
Hope it helps you a bit.
Related
I'm using Node(axios,pinia)+Vue3 as frontEnd,and node(express,bcrypt,jsonwebtoken)+MongoDB as BackEnd to build a SPA web.
I use JWT for login authentication and save at localstorage.
Now it only can keep login.
Hoping have Selectable "Keep Login" function like some forum usually have.
(After closing browser/shotdown will need to login again.)
I don't use sessionStorage for this website user often open new tab.Some cross tab problem bother me and I thought cookie might got better solution.
I can imagine only "Always login"/"temp login" can be done likes. But with selectable I can't thought a simple way to apply it.
Like now I'm thought still use LocalStorage(LS) for Vue to run,but also have Session Cookie(as Cookie)(Not sure the name but the cookiewill be deleted when all webs closed).
Keep login need no change for me.If set to temp login, then the setting will be save to JWT,all front/back could know.
Use cache as signal for closing browser,if (temp login)&&(no cookie){clear LS}.
However I wonder the localStorage can be extract so the func will not safty enough? Then a school computer will be disaster
I'm new to cookie/session,and want to know any better way for safty/efficent. I will prevent XSS.
It would be wonderful to have your experienct/Idea!
Poor language and consult at here first,If any describe not clear/too detail please tell me,I will try to edit it, thanks!
The use of JWT is below:
BackEnd use bcrypt verify user password and response a JWT(with userID for db to find,also save to user login record DB) and other basic user info.
Some response data like JWT,basic userinfo will be save in localstorage to let Vue decide display login/admin/different page.
When user send a request(some login-action), JWT will also be send as BearToken to bo verified by backEnd that JWT was record in that user login record.
So JWT is the only security key,the user's login record should have same JWT.
Because it save in localstorage,user must logout!(Despite I can set some limit time.)
I have a doubt regarding dynamically rendering the logged in user's name in the NavBar in react.
So my app is structured in the following way
<App>
<Header/>
<Router>
....
<Router/>
<Footer/>
<App/>
Now inside the header component, I need to display "Welcome <user>" whenever the user is logged in. Here are some solutions that I thought of,but Not sure if I'm missing out on anything.
To send it as a prop to the header. But it can only be dynamic if I do a setState in the App component and re render the entire app component (Which I want to avoid)
To store it in redux, so header can dynamically get the updated. But since I am using JWT, and the user needs to stay logged in, If the user refreshes the page, store content will be wiped out.
I can store the username in localstorage as well, but the entire app would still need to be re rendered in order to display the change
-) I think it can be accomplished in Angular by BehaviorSubject, but in this scenario, I'm clueless.
Is there any solution or method that I am missing?
Thanks in advance
At first if you want to keep your user logged in then you have to store the JWT somewhere. Here by 'somewhere' I mean, so that you can access it on next reload.
In my maximum project I store my JWT in local-storage. It works something like this
When user logs in I store the JWT in local-storage also in my reducer.
Then on my 'Inital State' I always take the local-storage so that if we have anything in the local-storage it means user is logged in
initial_state = {
userName: localstorage.getItem('user_name')
}
That's how you can keep your user logged in and at the time of logout erase the local-storage as well as the reducer.
You can send the user as a prop to the header. That is kind of the preferred method. Have the user login and save their app state with redux of the useState hook that is now available in React.
To your second question, JWTs preserve session data. Rerendering the page won't cause that to disappear. Well-designed apps have JWT with an expiration time (usually 20 minutes or less).
I worked on a voting application that did exactly what you're looking for and did not require any global state management. Feel free to pick through it. It's an open-source project. I think we used Auth0 or Google's Oauth library to do authentication.
Here's the code for the React header(navbar): https://github.com/poll-pal/poll-pal/blob/master/src/Components/Header/Header.js
Here's the code for the Express server that backed it: https://github.com/poll-pal/poll-pal/blob/master/server/routes/auth.js
I use Django Rest Framework with React on the frontend. I use Token Athentication and everything works fine. I now want to implement some permission based functions in my React frontend. More specifically, I want the author of a post to be able to edit the post, but all other users not. How can I achieve this?
My idea is that I add an is_viewing_own_story as a boolean to the user model in the django backend. When the author now clicks on the post, redux updates this state to 'true' and the buttons for deleting and updating stories appear (if is_viewing_own_story=true show buttons else show nothing).
I'm not sure if this is the smartest way or if there is a best practice?
If there is anything to read about, or any git hub repo to inform im happy to study that.
server should send user id for frontend and front check that id with current user
and
backend should set permissions for that api
like this :
class PostOwnerPermssion(BasePermission):
def has_object_permission(self,request,obj,**kwargs):
if request.user.id = obj.user.id:
return True
return False
I´m currently developing an application based on user authentication where each user can register a student-campus as a teacher and currently, I'm on a feature where I have two routes:
Route 1: It has a Datagrid where I'm listing all of the student campuses that I've already created and each row has an edit button that navigates to "Route 2" and the purpose of that is to edit the already created student campus.
Route 2: It has a form with all the necessary fields to create a student-campus.
As you can see I need to pass the student-campus ID to fetch data in the ngOnInit to fill the fields and be able to edit the above-mentioned, so I have several options in consideration:
Option 1: Pass ID in the URL.
this.router.navigate(['planteles/registrar', idPlantel]);
https://myapplication/planteles/registrar/1
Option 2: Pass ID in the URL with queryParams.
this.router.navigate(['planteles/registrar'], { queryParams: { ID: idPlantel } });
https://myapplication/planteles/registrar?ID=1
Option 3: Pass ID in the state object of navigation extras.
this.router.navigate(['planteles/registrar'], { state: { id: idPlantel } });
Option 4: Shared service and BehaviorSubject to subscribe to data.
I owe you the code
I'm able to use any of these but I have a problem with each one of them.
I can't use Option 1 and Option 2 because the ID cannot be changed by the teacher because that gives him the possibility to fetch the student-campus data of another teacher and edit it, so it isn't safe.
The problem with option 3 and option 4 is when I refresh the page the state is lost.
Currently, I have a workaround with option 3 which is to redirect the user to the previous page if the state is undefined but I don't like that solution. I'd like to persist data if the user reloads the page without using LocalStorage.
Thanks in advance, all help or contribution is well appreciated.
Option 1 is the correct option here (and the way you will find most sites in the real world are implemented... including this one we're on now). The problem is your approach to web security, and what you need to fix is your backend. You're approaching web security as though front end security is real, it's not. Web security exists on your backend. Users should not be able to fetch or view or manipulate data that does not belong to them, and this must be enforced by your backend.
A high level example of how this might work: some secure authentication token should be granted when the user logs in, then this authentication token should be attached to each request. The API then uses this token to check which user is making the request and ensures they have the proper permissions. If they do not (as in the case of the user editing their URL param to some ID they do not have permissions for) or if there is no token, the API should return a 401 or 403 response and the front end should handle it appropriately (ie sending them back to list, or showing an error page, whatever you decide)... how to issue this token, make it secure, and make use of it is an entirely separate topic beyond the scope of this answer.
In any of the options, I could open my dev tools, and view any API requests being made, and change the ID's and use that to view or manipulate other people's data without any effort at all. So options 3 / 4 are barely more "safe" than 1 or 2. As none of these are safe without properly implemented backend security.
Front end "security" exists only as user experience. Me and you are both using the same URL to view this page, but we see different options and buttons, like you can edit or delete your post and accept answers, while I can't, but I can edit or delete my answer etc. This isn't for true security purposes, SO's servers enforce who can and can't take what actions. It's just showing me and you the UI that reflects our different permissions, ie, its all just UX.
There's another way too, which is defined in Angular docs itself.
NavigationExtras
Example:
let navigationExtras: NavigationExtras = {
queryParams: {
"firstname": "Nic",
"lastname": "Raboy"
}
};
this.router.navigate(["page2"], navigationExtras);
I want to allow users to sign in/up via GitHub using firebase by clicking on the same button.
I create a new authentication for every user in the server side.
With the little piece of code, I'm able to detect if either the user is new or not:
const provider = new firebase.auth.GithubAuthProvider();
firebase.auth().signInWithPopup(provider).then((result) => {
if (result.additionalUserInfo.isNewUser) {
// The user is new
} else {
// The user is old
}
But, when the function signInWithPopup is called, if the user is a new user, a new authentication is automatically created for him. How can I avoid this?
And if the user is already authenticate, how can the user sign in from the client side? Where is the link between the authentication done from the back end with the user that wants to sign in the front end?
This is not how OAuth works. If you use an authentication provider like GitHub, they handle auth flow for you. The only thing that you are left with on the frontend side is an idToken with your identity, basic profile info, and a signature so you can as a user using this token. There's no distinction between sign up/sign in actions.
As you have noticed, Firebase is an extra layer in this flow, it creates an account for a user who signs in for the first time. But there's no user limit or extra payment so I wouldn't bother too much about these extra accounts. You might consider periodical cleanups if you care about the security here.
If you want to actually check if the user exists you have to use firebase-admin e.g. in a Firebase Function before the signInWithPopup is called. But still, unless you want to prevent users from signing up, you can hook your server logic into functions.auth.user().onCreate trigger.
To answer your last question, when the user is already signed in, you'll get the user object in firebase.auth().onAuthStateChanged when a page is loaded. Login state is stored by Firebase.js so once you have called signInWithPopup, you don't need extra steps.