Ignoring validation completely, since that is usually tackled first, there are three main layers of security to be checked when handling a user action:
1) Does the user have appropriate permission to perform the action? For example, if a user has a manager role, they can save an Invoice. This may be a simple role/permission check for access to the action, or a more complex business rule that is driven by a query from the database. Note that “permission to perform an action” (eg. “save”) is not the same as having permission to display the screen prior to performing the action (you could regard the “display” of that screen as an action as well). This wide granularity check is normally covered by web container role/permission realm security (see the [webapp.security.roles] role/permission section in this chapter).
2) Can the user do the action depending on the state of the data? For example, if an Invoice already has a state of “PAID” it cannot be paid again. This check is normally implemented by creating a state machine for the core business object. eg. public static boolean InvoiceStateMachine.canTransition(Invoice invoice, InvoiceState originalState, InvoiceState proposedState);
3) Can the user do the action depending on the ownership of the data? For example, if it is an Invoice that the user previously created but did not submit, can they “save” it? This can be rolled into a state machine, but since it usually requires a database query, a new class will have to exist on the application tier of the solution.
Where these checks will be happening in many places, or where the checks are particularly complex, it is best to define them in one place to ensure consistency and reliability.