1

I have to implement resource based access control in React application. My requirement as below.

I have defined authorization control in database like below for each page elements like buttons, input fields, labels. and these authorization controls will get assigned to users during user registration.

  1. PageName.userId.FieldName = 'Allow'

  2. PageName.DeleteButton ='Not-Allow'

  3. PageName.AddButton ='Allow'

  4. PageName.DeleteButton ='Allow'

When user logged-in, then application must bring all user mapped authorization and check against the visiting page elements and then allow user to view those elements.

Example: User Listing page, there will be edit user, delete User and update user button. In this page, few user will have access to delete button and few users will not have access to delete button. Like this, I must apply authorization logic to input fields like user Id input field should not be visible to certain users during edit user action.

My Implementation would be on each page render, I have to check what are page resource (Fields and buttons) exist in that page and then have to check whether the user having authorization to these resources or not.

What would be best way to implement these type of authorization ? As I have more than 300 pages in my application and each page I have to check these authorization and allow to user or not allow to user to do certain actions. Each page will have more than 10 elements (input fields and buttons.).

Seegel
  • 31
  • 4
  • Is your problem related to the pages quantity or how to convert the authorization matrix into react events? – JRichardsz May 25 '21 at 04:49
  • yes..how to convert these matrix into React event as I have 300 plus pages and I would like to have one utility which will act on each page to restrict the react element based on my authorization data. – Seegel May 25 '21 at 20:26
  • What is your react version? – JRichardsz May 27 '21 at 04:35
  • "react": "^16.13.1", "react-dom": "^16.13.1", "react-router": "^5.2.0", "react-router-dom": "^5.2.0", "reactstrap": "^8.9.0", – Seegel May 27 '21 at 05:46

2 Answers2

1

According to the comments, what you need is a react technique called: Higher Order Components in which an entire class is loaded before another component. Is in this class that you can write some lines to access to the json authorization object and enable or disable/hide some elements in your forms.

Flow could be:

  • After login form, you will exchange user/password with your rest api by a response like this:
{
  "token": "eyJhbGciOiJI",
  "forms": [
    "form1": {
      "allowedElements": {"DeleteButton","AddButton"}
    },
    "form2": {
      "allowedElements": {"CancelButton"}
    }
  ]
}
  • If response is success, store it and call to another route like home or something that your logged in user should see.
  • This route uses HOC so before its renderization, another class is loaded.
<Route exact path='/home' component={ConfigureFormElements(Home)} />
import React from 'react'

export default function(ComposedComponent) {

  class ConfigureFormElements extends Component {

    state = ...

    componentWillMount() {
    
    }

    componentWillUpdate(nextProps) {
      
    }

    render() {
      return <ComposedComponent {...this.props}/>
    }

  }

  return ConfigureFormElements

}
  • Choose the appropriate method to access to the object which contains the authorization data to enable and disable form elements.
render: function() {
    return (
      <button className={this.props.shouldHide ? 'hidden' : ''}>
        This will be hidden if you set <tt>props.shouldHide</tt> 
        to something truthy.
      </button>
    );
}

So if you have 300 pages, I assume that you have something like this:

<Route exact path='/page1' component={Page1} />
...
<Route exact path='/page150' component={Page150} />
...
<Route exact path='/page300' component={Page300} />

If you use HOC, you just need to add the ConfigureFormElements

<Route exact path='/page1' component={ConfigureFormElements(Page1)} />
...
<Route exact path='/page150' component={ConfigureFormElements(Page150)} />
...
<Route exact path='/page300' component={ConfigureFormElements(Page300)} />

Recommended lectures

JRichardsz
  • 14,356
  • 6
  • 59
  • 94
  • Instead of just hiding the DOM element, is there a way to not render the element? Definitely we can add conditional rendering, but is there a way where we can add some custom attribute to the element and handle showing/removing at app level based on this custom attribute. – kshashank Apr 13 '23 at 07:14
  • On a pure spa or csr, the rendering is performed with javascript at the web browser layer. If you have to exclude some forms before that, you have the ssr frameworks with java, c#, php, etc in which the form creation is made in the server and the entire html is returned https://stackoverflow.com/a/69511019/3957754 Also you can use some hybrids csr - ssr to to what you need – JRichardsz Apr 13 '23 at 14:11
0

All I can think of is to add display='none' or some css styling to disable the button/input on the front-end side. So you would have to somehow map the buttons either with inline style or with a component with props. I would recommend something like <Button auth={"some_auth_type_here"} buttonType={"some_button_type_here"}/>.

Additionally, I highly recommend server-side rejection for the authorization as well, since user could have direct access to api. Usually apis can be called from the url directly (i.e., google.com/api/session/killAllUser) which can lead to unexpected outcomes.

Seho
  • 61
  • 6
  • I omitted answer for how to do it for the 300 pages, since I don't know how you are exactly implementing the buttons and pages. Abstractly, I would use string from the router to first get the current page in useEffect and render buttons accordingly. – Seho May 25 '21 at 04:35