How to build authorization based systems with React? - javascript

I'm about to develop a application which will have some pages/components based on the authenticated user authorization/roles/permissions.
First of all: how to avoid having components different of <Login /> (for example) when a unauthenticated user access the app?
Them how to properly load different sets of components based on user's authorization? For example: only the users with manager role would be able to see <ManageUsers /> component. Only admins will see <Dashboard /> and so on.
This MUST to be handled by the server? I guess.
How is role-based apps built with React?(and I think the question extends for other client-side frameworks like Angular as well).

You can solve this problems either on the server-side or on the client. The main idea is to determine a user status and handle it. For example, you can redirect the user to the login page, show a warning message or allow the user to open the page.
On a server: you determine the user (through cookies, token etc) and his status. If it's okay then pass him on, if not - redirect e.g. to the login page.
About React and other frameworks/libraries: again you need to determine the user status. You can do this by sending API request or getting stored data in localstorage etc. There're several approaches how to do it (the 1st way is better in my opinion):
Through the router. In a React app you can use react-router and onEnter hook. Here an example. In short, when route is matched the onEnter hook will be called and there you can do whatever you want
By server response. If it's a SPA then you probably need to load some data to show the page. So, if the user isn't authenticated or can't get this data the server should return 401 (not authenticated/not logged in) or 403 (not authorized) status. And again you just need to handle this.
That's all about allowing a user to open a page. But what about displaying different blocks on the page for different users? Let's say we need to show different set of links in the header for authenticated user and admin. How it might look with React:
const Header = React.createClass({
render() {
return (
<header>
<a className="logo" href="/">Logo</a>
// here you get the user role from the Flux store, localstorage or whatever you want
{user.role === 'admin' ? this.renderAdminLinks() : this.renderAuthLinks()}
</header>
);
},
renderAuthLinks() {
return (
<ul>
Dashboard
Profile
</ul>
);
},
renderAdminLinks() {
return (
<ul>
Admin Panel
Statistics
</ul>
);
}
});
It's just an example but for more complicated things you can define new components like <AdminLinks/>, <UserLinks> and so on.
The the same idea will work with Angular/Backbone/etc in the component/view you should decide what you want to show to the user based on his status.

Related

Accessing react components directly from URL

I am trying to create an new react app. I have 3 components: app (with login functionality) , admin and client.
How can I render (redirect to) admin / client based on a value (user role) , after successfully login?
Is this any way to access the admin / client components directly from the URL? More specific, localhost:3000 takes me to App.js (witch makes sense, because it is defined like this in index.js). If I want to see directly the admin component (hijacking the login), can I use for example localhost:3000/admin ? how can I do that?
Thank you !
You can use react router and in particular route.push('/admin')
You need to define the '/admin' route and voilà.
To bypass the login, you may want to make a 'test-admin' route and a private 'admin' route. Here is how to make a private route if you happen to need it:
https://dev.to/karanpratapsingh/private-public-and-restricted-routes-in-react-42ff
You can use react-router, that allow to define some route based on URL.
When you have a login feature, then you would probably wants to have some protected route, that are only accessible when you are logged in.
Then I recommend you to read this article

React-Firebase Authentication

I am having a react application with firebase as authentication. My authentication code is below
await firebase.auth().onAuthStateChanged((user) => {
if (user) {
props.setUser(user); //setting the user if login/register happens
history.push(`/admin/dashboard`);
console.log("user",user)
} else {
props.setUser(null); //blocks the user to get into the app if he/she is not logged in
history.push("/");
}
});
So, when user logs in..he will be navigated to /admin/dashboard. suppose when am in /admin/home and when i refresh the page, it goes again to admin/dashboard which shouldn't happen. so I tried
history.push(${props.location.pathname}); it works correctly after the refresh, it stays on the same page when the application is logged in. but when I restart the server again when I try to log in, it says no redirect url is specified. Got stuck on this for a long time.. Any help is welcome.Thanks
What your code does is check if the user is logged in and only let the user access the data if so.
You should do that in the fireabse rules (= serverside) as this is way more secure.
You didn't provide the kind of FirebaseDB you are using. So assuming you use the Realtime Database here are some according rules:
{
“rules”: {
“.read”: “auth != null”,
“.write”: “auth != null”
}
}
You should maybe check the rules before deploying your app, because now every authenticated user can change/add/delete data, but you get the point. This does exactly what you want so you won't even need to perform a check in your ReactJS App. Firebase will automatically deny unauthenticated users the access to the database.
Btw: You should try to implement security relevant things in the Firebase Rules. Ideally you want your rules to be written in a way that you don't need to perform any validation inside your ReactJS app. Firebase rules can get quite complex. I experienced that myself when writing a chat app with chatrooms and everything. But it is definitly worth the effort if your app is more secure after.

Restrict access to the authentified user

I'm creating my first application using Laravel and React.
I followed a tutorial online, and I noticed that the authentification, unlike what I was used to with only Laravel, is using localStorage instead of Auth::user.
With the following line I can get the informations of the authentified user :
const user = JSON.parse(localStorage.getItem("userData"));
I can access the info of the logged user like this :
{user.id}{user.name}{user.email}
Now in my application, each profile belong to a user.
Using react and react-routes, to access a profile, the user need to provide idof the profile in the addition of the url, like this :
<Route path="/customize/:id?" component={Home} />
The current problem is that any user can view any profil. I want to limit the privilege to see/modify the profiles to ONLY those who are related to the profiles. So when the user is logged, he can only manage his own profiles, or perhaps the profiles that have the sameuser_id as his id.
I searched and I found that I have to use Middlewares I think to manage the access, but I'm not entirely sure.
You're right, you should use a middleware to verify the user is authenticated.
I don't know which way you're using to authenticate a user.
Basically if you're using laravel built in authentication you should be able to use the default auth middleware as described here: https://laravel.com/docs/8.x/authentication#protecting-routes
Otherwise you may need to create a new middleware to handle the verification, the process of making a new middleware is described here: https://laravel.com/docs/8.x/middleware
Then you can use the middleware method on the routes you'd like to protect
Route::get('/customize/{id}', function () {
// Only authenticated users may access this route...
})->middleware('auth');
Another solution I would not recommend for this use is doing a simple Auth::check() in your controller's function

Prevent navigation to certain pages/routes

I have a Next.js (fix may not necessarily have anything to do with Next.js) app that I want to limit some navigation. This page in the Next.js docs mentions "you should guard against navigation to routes you do not want programmatically", but I'm unsure how to do this. Let's say I have the following pages:
/bikes
/boats
/cars
and I only want to allow a user to see /bikes. How would I be able to do this. I'm able to redirect from an undesired page to an acceptable page, but only after the undesired page loads. Is there a way to redirect before this (maybe by changing the URL as soon as it is changed)?
I appreciate that this is an old question, however, I wish I had known this answer to it earlier than I did, so I would like to answer it for the record.
Our next.js app had a relatively complex set of permissions associated with accessing each page (with the ability to access the page, or different data presented on it) based on the authentication status of a user as well as the authorization scopes granted to them.
The solution that we used was the to return a redirect from getServerSideProps(). Normally one would return something like the following:
const getServerSideProps = (context) => {
return {
props: {
myProp: 1
}
};
}
However, it is also possible to return a redirect. This redirect is performed on the server side prior to the page content being sent to the browser:
const getServerSideProps = (context) => {
return {
redirect: '/login'
};
}
This is relatively new functionality - it was only pulled in towards the end of last year, and there isn't much documentation for it anywhere, but it perfectly serves this use case.

Access React app from other React app on the same page

I have a situation where I have written the front-end of my website as micro-services. Every functional section of my website is a react-habitat application bundled with css and html. I have done this so I can re-use these sections wherever I want on the site.
My problem is however in the checkout area I need to pass the customerId from the login application (on successful response) into the delivery address application so I can bring back the default address. I don't want to create a new application and duplicate the code for login and delivery address applications because I will need to use them elsewhere on the website.
So my question is. How can I pass this customerId from my login application to my delivery address application without a page reload? Is there a way to access a react application method from outside of that react application?
Login click handler:
clickHandler(e) {
e.preventDefault();
let payload = {"email":this.props.email, "password":this.props.password};
AuthenticationApp.login(payload).then((response) => {
if (this.props.referrer === "checkout") {
$("#checkout_login-register-tab").addClass("done");
$("#checkout_login-delivery-tab").removeClass("todo");
// Temporary hack to reload page until we can pass new user session into delivery/billing react app from here.
location.reload();
}
this.props.updateParentState({isLoggedIn: true});
})
.catch(function(response){
console.log("res2 - catch", response)
});
}
I have forced a page reload here so the delivery address application re-renders and picks up customerId from the service. I need a way to re-render the delivery application at this stage (from this separate application), either by accessing a function somehow or forcing the application to reset? Is this possible or is there a workaround other than a page reload?
You can do something like this:
loadDeliveryApp(data) {
ReactDOM.render(<DeliveryApp data={data} />, document.getElementById('delivery-app'))
ReactDOM.unmountComponentAtNode(document.getElementById("login-app"))
}
clickHandler(e) {
e.preventDefault()
// your login stuff
loadDeliveryApp(data)
}
Here is the working demo.
https://codepen.io/madhurgarg71/pen/dzgxMd
I'm the original creator of React Habitat.. all your applications can talk to each other via either a flux observer or something like redux.
I suggest flux for react habitat normally as the individual stores keep it light weight instead of one BIG store in redux where you might have dead code in a habitat situation.
You will need to create one common store that both your applications import so that if one changes it, the other will get the update. I can put a demo together later if that helps.

Categories

Resources