Best practices for control permissions?

2019-02-07 13:22发布

问题:

Hey all, I need some advice on this...

We have certain permissions setup in the database for certain levels of control a user can have over the application. Disabled, ReadOnly and Edit.

My question is: Are there more generic/better ways to handle permissions applied to a form element on the page than writing a security method/check per page to enable/disable/hide/show proper controls depending on the permissions allowed?

Anyone have any experience handling this in different ways?

Edit:

I just thought about the possibility of adding constants for each layer that needs security and then adding an IsAuthorized function in the user class that would accept a constant from the form that the control is on, and return boolean to enable/disable controls, this would really reduce the amount of places I'd have to hit when/if I ever need to modify the security for all forms.

Cheers!

回答1:

Sorry for going slightly off-topic here, but learn from my mistake:

I had a simple web app one time that I was developing and I thought that I'd setup 3 levels of security: limited read-only (public), read-limited write (user), read-write (admin). The users table had a level of security in it and everything worked fine... until I needed finer control over security levels as the project grew. It all started with a user that needed more than user control in one area of the program but not full admin control.

What I should have done was setup an expandable system with finer control even though I didn't need it at first. This would have saved me sooo much time.



回答2:

I think there are more possibilities than you are considering.

  • Hidden/Visible - is the field visible or not
  • Blanked/System/Unchanged - does the system initially set the value to blank, or to some business-rule-provided value, or is it left as-is
  • ReadOnly/Editable - can the user change the value
  • Required/LeaveBlank/Optional - is the field required to not be blank, or can it be left blank assuming it was blank to begin with, or is it optional and can be blank in any case

Also you need to consider a lot of factors that go into making the decision

  • Role - usually the user has 1 or more roles, and those roles can allow or disallow different possibilities
  • Status - the status of the object in question often controls which fields are editable, regardless of role
  • Object - often the values of the object itself determine what is allowed when, beyond just's it's status
  • Task - you might break down editing things into more than just read and edit
  • Section - I often want to control the settings for an entire section of the object or screen, and all the controls inherit those settings, but can override them on an individual basis if needed

Implementation? First, make sure you have a clear vision of how the page lifecycle is handled. Mine usually goes something like this.

  • Get the object they are editing, usually from session state, sometimes if they are doing a "new" operation you may need to create a stub data structure for them to work on
  • If this is the first time the page is loading up, populate choices into dropdowns, this is usually a generic process, done only once
  • If this is a postback, update the object being edited by reading in values off the controls
  • Process events such as button clicks
  • Run through all your business edits, these should alter the data structure they are editing
  • Update the visibility and editability of the controls based on all the data you have on hand
  • Populate the controls with the data from the object being edited, including validation messages, or error messages


回答3:

You may want to check how django handles forms and validates them. Forms are handled like models, they have their own class, so their field list, validation rules and display logic is no more scattered throughout the view, the controller and the helper. With such a structure, it's pretty clear where the hidden/readonly/editable logic belong.

It seems that such a feature is not yet implemented in rails. It's not only a time-saver, it keeps your code clean and structured. You could start by creating a base class for forms, where validation is separated from the controller.



回答4:

To work properly, I have found that access levels should be in this increasing order: NONE, VIEW, REQUIRED, EDIT.

Note that REQUIRED is NOT the top level as you may think it would be since EDIT (both populate & de-populate permission) is a greater privilege than REQUIRED (populate-only permission).

The enum would look like this:

/** NO permissions.
 *     Presentation: "hidden"
 *     Database: "no access"
 */
NONE(0),

/** VIEW permissions.
 *     Presentation: "read-only"
 *     Database: "read access"
 */
VIEW(1),

/** VIEW and POPULATE permissions.
 *     Presentation: "required/highlighted"
 *     Database: "non-null"
 */
REQUIRED(2),

/** VIEW, POPULATE, and DEPOPULATE permissions.
 *     Presentation: "editable"
 *     Database: "nullable"
 */
EDIT(3);

From the bottom layer (database constraints), create a map of fields-to-access. This map then gets updated (further restrained) at the next layer up (business rules + user permissions). Finally, the top layer (presentation rules) can then further restrain the map again if desired.

Important: The map must be wrapped so that it only allows access to be decreased with any subsequent update. Updates which attempt to increase access should just be ignored without triggering any error. This is because it should act like a voting system on what the access should look like. In essence, the subsequent layering of access levels as mentioned above can happen in any order since it will result in an access-level low-water-mark for each field once all layers have voted.

Ramifications:

1) The presentation layer CAN hide a field (set access to NONE) for a database-specified read-only (VIEW) field.

2) The presentation layer CANNOT display a field when the business rules say that the user does not have at least VIEW access.

3) The presentation layer CANNOT move a field's access up to "editable" (nullable) if the database says it's only "required" (non-nullable).

Note: The presentation layer should be made (custom display tags) to render the fields by reading the access map without the need for any "if" statements.

The same access map that is used for setting up the display can also be using during the submit validations. A generic validator can be written to read any form and its access map to ensure that all the rules have been followed.

(Also see thread: Best Practices for controlling access to form fields)