Introduction: The Quest for Simpler, Safer Data Access
Keeping an application's data safe and ensuring the right people see the right information is a top priority for any developer. At its core, this often means controlling which rows of data a user can access based on who they are or what their role is. This is known as row-level security.
Code On Time has always given developers tools to build secure applications. However, some of the established ways of doing this had their trade-offs. One method, using Filter Expressions on views, is easy for simple cases but can become a headache to manage if you have many views that all need the same security logic. Changing a rule might mean editing it in many different places. Another powerful method involves writing custom C# or VB.NET code for Dynamic Access Control Rules. This gives complete freedom to create any security setup imaginable, but it also means developers need to be comfortable with coding, and these rules can be harder to find and review because they're part of the program code itself, not a visible configuration.
To address these challenges, Code On Time now offers Static Access Control Rules, or SACR. This is a new way to define your security rules that focuses on clear, declarative statements. Instead of writing extensive code for common scenarios, you define these rules in a central configuration file (touch-settings.json
), using SQL
– a language many are already familiar with. This approach makes it much easier to set up, check, and fix security for common situations, especially with the help of the visual tools provided in App Studio, which allow for instant testing and configuration.
This tutorial will guide you through:
- A step-by-step guide to implementing SACR in a sample Northwind application.
- How App Studio enhances the SACR experience.
- Why SACR is a superior approach for many common security needs.
- How the unique architecture of apps built with Code On Time makes SACR possible.
- The different ways to restrict data access and where SACR fits best.
Target Audience: This tutorial is for application developers, database administrators, security configurators, and anyone responsible for ensuring data is appropriately secured in applications built with Code On Time.
Tutorial: Securing Northwind Data with SACR
Let's walk through a practical example. We'll build a simple application using the Northwind database and then apply Static Access Control Rules to secure its data.
The diagram shows the Orders
, Customers
, Employees
, and Shippers
tables in the Northwind database. The security system setup will rely on the match of the employee’s LastName
to the name of the application user.
Prerequisites:
- Create a Code On Time Project:
-
- Start the Code On Time application generator.
- Create a new project following the steps outlined in the tutorial.
- When prompted for the database, connect to a Northwind database.
- In the Data Model & Business Logic step, create a data model for
Orders
and proceed to create the suggested models for the Customers
, Employees
, and Shippers
for completeness, though we won't directly apply SACR to the latter in this tutorial.
- Enable ASP.NET Membership:
-
- Ensure your project is configured to use ASP.NET Membership when setting up the database connection string.
- Create Users and Assign Roles:
-
- Once the application is generated for the first time and displayed in the default web browser, sign in as the user
admin
with the password admin123%
- Use the built-in user management features of the Membership page (usually accessible to an administrator) to create the following users and assign them to roles:
-
- User:
Fuller
, Password: user123%
, Role: Users
(In the Northwind database, Andrew Fuller is EmployeeID 2
)
- User:
Davolio
, Password: user123%
, Role: Users
(Nancy Davolio is EmployeeID 1
)
Step 1: Locating the SACR Configuration in App Studio
All Static Access Control Rules are managed directly within App Studio, which is embedded in your live application.
- Navigate to the “Employees” page.
- If you do not see the App Studio toolbars surrounding the app, then select the “App Studio” menu option in the system context menu of your app.
- Click the “Search” button on the top toolbar of the App Studio and enter
Access Control Rules
in the search prompt. Select the first option in the search result.

- You'll see the App Explorer panel with the Server / Access Control Rules configuration node selected in the Settings section.
Enter access control
in the search prompt to locate the SACR configuration section. Alternatively, navigate directly to the Settings / Server /Access Control Rules
in the App Explorer.
Step 2: Restrict Employees to See Only Their Own Record
Our first security task is to ensure that when an employee (like "Fuller" or "Davolio") logs into the application, they can only see their own record on the Employees page. We will achieve this by comparing the LastName
field in the Employees
data controller with the logged-in user's UserName
.
- In App Explorer, with the
Access Control Rules
node selected (from Step 1), locate the Actions
section in the Properties.
- Click the "Add Rule" link to create a new rule. The corresponding node will become selected in the Settings hierarchy.
- Configure the properties for this rule as follows:
-
- In the Trigger category:
-
- Field: Enter
LastName
. (The Employees
data controller in Northwind uses LastName
as the field name for the employee's last name).
- Equals: From the dropdown list, select
User Name
. (This tells the application to compare the LastName
field with the current user's login name, automatically setting the internal SQL
value or the rule to the built-in @BusinessRules_UserName
parameter).
- In the Effect category:
-
- Filter: Ensure this is set to
Include If Match
. (This is the default Filter
mode, meaning data rows will be included if the LastName
matches the user's UserName
).
- (Optional) In the Why category:
-
- Comment: Enter a descriptive comment, for example:
Employees can only view their own record.
- All changes are saved automatically. You will see that the live application is grayed out indicating a changed state.

Testing Step 2:
- Close the App Explorer and click the “frozen” (grayed out) application to reload.
- Log out of the application if you are logged in as admin.
- Log in as
Davolio
(password: user123%
).
- Navigate to the "Employees" page. You should now see only one record: the record for Nancy Davolio.
- Log out.
- Log in as
Fuller
(password: user123%
).
- Navigate to the "Employees" page. You should now see only one record: the record for Andrew Fuller.
- Log out.
- Log in as
admin
(password: admin123%
).
- Navigate to the "Employees" page. At this point, you will likely see no employee records. This is because the rule we just created applies to all users by default (since we didn't specify any
roles
for it), and there is no employee record where the LastName
is "admin". We will address how administrators can bypass these rules in a later step.
This access control rule is triggered by the presence of the LastName
data field in the view. The framework will filter in the rows that have the trigger field value that matches the user’s name. The rule applies to the views of all existing and future data controllers of the application.
Step 3: Restrict Orders to the Logged-in Employee
Next, we want employees to only see the orders they are personally responsible for. The Orders
data controller in the Northwind sample includes an EmployeeLastName
field.
- Navigate to the “Orders” page and click the “Inspect” button (crosshair icon) on the top toolbar of the App Studio. The icon will transform into an arrow, and the tooltip will read "End Inspection".
- Click the name of the employee associated with any order record. The App Explorer will appear with the
EmployeeID
field selected. The parent “Data Field” node with the same name uses the EmployeeLastName
as an alias for the EmployeeID
in the Orders
.
- Copy the value of the
Alias
to the clipboard.

- In App Explorer, select the
Settings
tab.
- Add another rule to the
Access Control List
.
- Configure the properties of the new rule node:
-
- In the Trigger category:
-
- Field:
EmployeeLastName
- Equals:
UserName
- In the Effect category:
-
- (Optional) In the Why category:
-
- Comment:
Restrict orders to those managed by the logged-in employee.
- Changes are saved automatically. This is how the rule may look.

Testing Step 3:
- Refresh your application preview.
- Log in as
Davolio
. Navigate to the "Orders" page. You should only see orders where Nancy Davolio is listed as the employee.
- Log out. Log in as
Fuller
. Navigate to the "Orders" page. You should only see orders where Andrew Fuller is listed as the employee.
- Log in as
admin
. You should still see no orders.

The Include If Match
filter of the access control rule restricts access to the orders that have the employee’s last name match the user’s name. Users Davolio
and Fuller
will see their own orders only. The admin
user will see no orders on the “Orders” page.
Important Consideration for this Step: Since this rule uses EmployeeLastName
as the trigger field with Equals: UserName
and has no Controllers
or Roles
restrictions, it is virtually identical to the first rule created in Step 2 with the exception of the trigger field name. If you rename the LastName
field in the Employees
controller to EmployeeLastName
, then the second rule will apply to both Employees
and Orders
controllers making the first rule unnecessary. The current setup relies on the EmployeeLastName
field being consistently available and sufficient for identifying the employee for orders or any other controller with the same data field.
Step 4: Restrict Customers Based on Their Employee's Orders
This rule is more advanced. We want an employee to only see Customers
for whom they (the employee) have placed at least one order. The Customers
data controller does not directly contain EmployeeLastName
or EmployeeID
. Therefore, we'll use the CustomerID
field as our trigger and provide a custom SQL subquery.
- In App Studio, click the “Settings” quick access button at the bottom of the right toolbar. Navigate to
Server / Access Control Rules
and add a new rule.
- Configure the properties of the new rule:
-
- In the Trigger category:
-
- Explanation: This query selects all unique
CustomerID
s from Orders
linked to the current user's UserName
.
- In the Effect category:
-
- Filter:
Include If Match
(A customer is included if its CustomerID
is IN
the list from the subquery).
- (Optional) In the Why category:
-
- Comment:
Show customers only if the logged-in employee has placed orders for them.
- Review the rule before you try it out.

Testing Step 4:
- Refresh the application.
- Log in as
Davolio
. Navigate to the "Customers" page. You should only see the 65
customers for whom Nancy Davolio has handled orders (the total number of customers in the sample data set is 91
).
- Log out. Log in as
Fuller
. Navigate to the "Customers" page. You should only see the 59
customers for whom Andrew Fuller has handled orders.
- Log in as
admin
. You should still see no customers.
Step 5: Granting Full Access to Administrators
Our admin
user, who is in the Administrators
role, currently cannot see any data in the “Employees”, “Orders”, or “Customers” pages because the SACR rules we've created apply universally by default. We need to exempt users in the Administrators
role from all SACR filtering.
- In App Explorer, navigate to the
Settings / Server / Access Control Rules
node (select the Access Control Rules
node itself, not the rules in the collection under it).
- Find the
Full Access
property.
- In the value field for
Full Access
, enter the role name: Administrators
(If you had multiple roles needing full access, you would enter them as a comma-separated list, e.g.,
Administrators, SuperUsers).
Testing Step 5:
- Refresh your application preview.
- Log in as
admin
.
- Navigate to the "Employees", "Orders", and "Customers" pages. You should now see all records on each of these pages. The
Full Access
setting effectively bypasses all defined Static Access Control Rules for users in the "Administrators" role.
- Log out and log back in as
Davolio
or Fuller
. Confirm their access is still correctly restricted according to the SACR rules – they should only see their respective data.
App Studio Integration: Visualizing and Debugging Security
App Studio 2025 is designed to make working with complex configurations such as Static Access Control Rules not just possible, but intuitive and efficient. Here’s how it helps:
The "Security Shield" Icon: An At-a-Glance Security Check
As you define and enable SACR, App Studio provides immediate visual feedback directly in the App Explorer tree. You'll start seeing a "security shield" icon (magenta color for SACR) appearing as an overlay on relevant nodes:
- Controller nodes (like
Employees
, Orders
, Customers
in our tutorial) will display the shield if any SACR rule is potentially active for that controller.
- View nodes (like
grid1
, editForm1
under a “secured” controller) will show the shield if they contain data fields that are designated as trigger fields in active rules.
- Data Field nodes (listed within a view definition) will show the shield if that specific field's name matches a trigger field in an active rule.
This icon serves as an At-a-Glance Security Check. The principle is simple and powerful: "no shield = no SACR applied here." As you browse your application structure, you can instantly see which parts are covered by your declarative security rules. When you add a new data controller, if it naturally includes a common field like UserID for which you have a global SACR, it will automatically appear "secured" with the shield icon. If it doesn't, its lack of a shield prompts you to consider if security rules are needed.
The maroon “security shield” icon is overlaid on the relevant configuration nodes of Customers
, Employees
, and Orders
data controllers. The icon subtly hints of the security restrictions in the application making it possible at-a-glance security check. The Access Control
property group of the affected nodes contains the Triggers
property with the list of relevant “trigger” fields defined in SACR.
The “Triggers” Property: Understanding Rule Impact in Context
When you select a node in the App Explorer that displays the security shield (be it a controller, a view, or a data field within a view), look at its properties in the Properties grid. You will find an Access Control category. Inside this category, there's a read-only property named Triggers
. This property lists the actual trigger field names from your active SACR rules that are relevant to the currently selected item.
- For a controller node,
Triggers
lists all trigger fields defined in that controller's fields that are used by SACR rules applicable to this controller.
- For a view node,
Triggers
lists trigger fields that are present in that specific view and are used by applicable SACR rules.
- For a data field node (within a view), if its name (or alias) matches a trigger field in an active rule, the
Triggers
property will show that field name.
This Triggers
property tells you exactly which of your SACR trigger fields are causing rules to be evaluated for that part of your application. For example, if the Orders
controller's Triggers
property shows EmployeeLastName
(from our rule in Step 3) and also CustomerID
(because the rule from Step 4 was not scoped only to the Customers
controller, and the Orders
views contained CustomerID
), this alerts you that two different types of filtering logic are being applied. The shield icon indicates some rule applies; the Triggers
property specifies which fields are the activators. The "first rule wins for this specific trigger" logic applies, so one rule will be chosen for EmployeeLastName
, and one for CustomerID
if it's also a trigger.
"Access Control Rules" Action and Refining Rule Scope: A Practical Example
To make it even easier to connect an application element to its security, when a node (controller, view, or data field) in the App Explorer displays the security shield icon, a special "Access Control Rules" action link becomes available. You'll find this link in the "Actions" section that appears below the Properties grid when the node is selected. It's also typically available in the node's right-click context menu.
Clicking this "Access Control Rules" action is a direct shortcut. It instantly navigates you within the App Explorer to the first matching Static Access Control Rule (from your Settings / Server / Access Control Rules
list) that affects the item you had selected. This provides a quick jump from seeing that an element is secured to inspecting the actual rule responsible. You can then use the standard Back and Forward toolbar buttons (usually found above the App Explorer) to easily navigate between the rule definition and the application structure you were previously viewing.
Let's use this shortcut to refine our CustomerID
rule.
The Problem: As observed in the previous picture, our CustomerID
-triggered rule (intended for the “Customers” page) is currently global. If the Orders
controller views include CustomerID
, this rule will also apply to orders. While the subquery specified in the SQL
property of the rule would still correctly filter the CustomerID
list based on the employee, applying this complex subquery to Orders
is unnecessary and less efficient than the direct EmployeeLastName = @BusinessRules_UserName
comparison already handled by our other rule for Orders
. The EmployeeLastName
rule is sufficient and more performant for filtering orders.
The Solution: Scoping the
CustomerID Rule
- To find this rule, you could select the
CustomerID
data field and click the "Access Control Rules" action (found below the Properties grid or in the context menu). This action navigates you to the first matching rule for the first trigger field listed.

- Alternatively, and more directly for this refinement task: Navigate in the App Explorer to
Settings / Server / Access Control Rules
and select the rule you created in Step 4 (the one with triggerField: CustomerID
and the SQL subquery).
- In the Properties grid for this
CustomerID
rule, go to the When category.
- Find the Controllers property.
- Enter
^Customers$
in the value field. This regular expression ensures the rule only applies if the controller name is exactly "Customers". For simpler cases with no ambiguity, just Customers
would also work, but ^Customers$
is more precise for complex applications. The regular expression specified in the Controllers
property is evaluated as case-insensitive.
- Click the Back button in the toolbar above the tree and you will be transferred back to the
Orders / views / grid1 / CustomerID
. There will be no security shield on the data field node.
Easy Debugging with the “Enabled” Property
One of the most significant advantages of SACR, especially when managed through App Studio, is the ease of debugging. If you find that data isn't being filtered as you expect, or perhaps too much data is being hidden:
- Use the “Inspect” feature of the App Studio to locate the configuration elements related to the data you are viewing in the live application.
- Locate the “secured” node of the data controller.
- Use the "Access Control Rules" action (or navigate manually in the App Explorer) to find the rule(s) you suspect might be causing an issue.
- Select the specific rule node in the App Explorer.
- In its Properties grid, go to the Effect category and set the
Enabled
property to No
.
- Refresh your live application preview in the browser.
This temporarily deactivates the rule. If the data visibility issue is resolved (or changes in a way that points to this rule being the cause), you've quickly isolated the problematic rule. You can then re-examine its Trigger
, Effect
, and When
configurations. This iterative process of toggling rules is vastly simpler and faster than stepping through complex server-side code or examining the filter expressions in the views. Make sure to document the rule configuration changes in the Why
section.

The disabled access rules are shown with a “snoozed” overlay icon that replaces the “security shield”. Use this property to debug the individual rules. Double-click.the Enabled
property and click on the “frozen” application to have it reload with a new set of rows. Click the “Settings” quick access button at the bottom of the right toolbar in App Studio to continue the investigation of the SACR effect on the row-level filtering.
Finding Where Rules Apply: The "Related Items" Action
Understanding the full impact of a SACR rule means knowing all the places in your application where its trigger field is used. App Studio provides a powerful universal feature called Related Items
to help you do just this.
When you have a specific SACR rule selected in the App Explorer (under Settings / Server / AccessControl Rules
), you can find the Related Items
action in its context menu (usually by right-clicking on the rule node). An icon for this action is also conveniently available on the toolbar above the App Explorer tree.

Selecting the Related Items
action for an SACR rule performs a global search across your entire application's configuration. This search is automatically focused on finding every instance where the trigger field of your selected rule is defined as a data field in any view across all your data controllers.
The search results will then list these data field nodes. Importantly, if these located nodes are themselves affected by this or other SACR rules (meaning they would display the "security shield" icon in the App Explorer), that shield icon will also appear next to them in the search results.
This allows for an easy and comprehensive review of all the data objects directly impacted by a specific SACR rule, directly from the rule's definition. It helps you quickly assess the scope of a rule and ensure it's being applied exactly where you intend, and nowhere else.
The Related Items
action is available on many configuration nodes in the App Explorer. It is very useful in the context of an access control rule when the global search is activated with the search prompt that yields the possible matches. At-a-glance you can see the affected data fields and those that are not in the range of the rule.
The Code On Time Advantage: A Foundation for Smart Security
The effectiveness of Static Access Control Rules in Code On Time is deeply rooted in its foundational architecture. Understanding this helps appreciate why SACR is not just another feature, but a natural extension of the platform's design.
At the heart of every Code On Time application are Data Controllers. These are not just simple table mappings; they are rich XML files that act as a comprehensive metadata layer for your database entities – their fields, the commands used to fetch and modify data, the various ways data can be displayed (views), and the actions users can perform.
Layered on top of this is the application's server-side framework, often referred to as the Data Aquarium. This framework is a universal engine. When a user interacts with the application – say, opens a page to view orders – the Data Aquarium doesn't just execute a pre-written SQL query. Instead, it dynamically composes the necessary SQL
(SELECT
, INSERT
, UPDATE
, DELETE
) at runtime. It does this by interpreting the data controller's definition in the context of the user's request and current application state.
This dynamic SQL composition provides perfect, natural interception points. Before the framework builds the final SQL query to fetch data for a particular view, it knows exactly which fields are being requested for that view. This is the precise moment where SACR integrates seamlessly and powerfully. The framework can:
- Examine the list of fields being requested for a data view.
- Consult your central
touch-settings.json
configuration file to see if any Static Access Control Rules are "triggered" by the presence of those specific fields.
- If a matching rule is found (and other conditions like user roles are met), the framework automatically injects that rule's SQL filtering logic (its
WHERE
clause conditions) directly into the dynamically generated query.
This automatic, framework-level application of rules is key. It ensures that security logic is applied consistently across your application without requiring you to manually edit every single controller or view. You define a rule once, and it applies everywhere the specified conditions are met. This inherent capability of the Code On Time architecture makes SACR an exceptionally efficient and reliable security mechanism. Many other application development tools require developers to explicitly add security conditions to every data query or screen, which is error-prone and hard to maintain. SACR, by leveraging the data controller metadata, provides a more holistic and "Don't Repeat Yourself" (DRY) approach to security.
Choosing Your Tool: SACR, Code Rules, and View Filters
Code On Time provides a layered approach to data restriction, allowing you to select the most appropriate tool for each specific need. It's crucial to understand the distinct purpose of each:
- Static Access Control Rules (SACR) - Recommended for Security Filtering:
-
- Purpose: This should be your primary tool for all security-related row-level data filtering. Use SACR to ensure users only see the data records they are explicitly authorized to access based on their identity (e.g.,
UserID
), their assigned roles (e.g., "Managers", "Sales"), or other criteria defined via SQL expressions.
- Method: Rules are defined declaratively as JSON objects within the
touch-settings.json
file. App Studio provides a user-friendly visual interface for creating and managing these rules.
- Why it's superior for this:
-
- Centralized & Visible: All security rules are in one place, making them easy to find, audit, and understand.
- Leverages SQL Skills: You define the core logic using SQL, a common and powerful language for data manipulation.
- Maintainable & Debuggable: Changes are localized. Debugging is often as simple as temporarily disabling a rule in App Studio to see its effect.
- Automatic Application: Rules apply automatically to any new data controllers or views that include the specified "trigger" fields, ensuring consistent security as your application grows.
- "Database Friendly" Performance: Rules translate directly into SQL
WHERE
clauses, allowing your database engine to perform the filtering efficiently using indexes and its optimizer. This is generally more performant than fetching large datasets to the application server and then filtering them in memory, a common pattern in some other frameworks.
- Dynamic Access Control Rules (Code-Based) - For Advanced or "Exotic" Security Logic:
-
- Purpose: Reserve this powerful method for security requirements that are too complex or "exotic" and cannot be easily expressed with SACR's declarative SQL approach. This is for scenarios requiring procedural logic, calculations not easily done in SQL, interactions with external systems as part of the access decision, or highly dynamic conditions.
- Method: Implement these rules by writing C# or VB.NET code within your project's
SharedBusinessRules
class (or a controller-specific business rules class). Typically, you override the EnumerateDynamicAccessControlRules
method and use RegisterAccessControlRule
calls to inject your custom logic.
- Example: A classic "exotic" requirement is restricting access to certain data based on the time of day. For instance, allowing access to sensitive financial reports only during business hours (e.g., 8 AM to 5 PM).
C#
1234567891011121314151617181920212223// Simplified conceptual example within a BusinessRules class
protected override void EnumerateDynamicAccessControlRules(string controllerName)
{
// It's good practice to call the base method to ensure SACR are processed
base.EnumerateDynamicAccessControlRules(controllerName);
if (controllerName == "FinancialReports") // Apply only to specific controller
{
TimeSpan now = DateTime.Now.TimeOfDay;
TimeSpan businessStart = new TimeSpan(8, 0, 0); // 8 AM
TimeSpan businessEnd = new TimeSpan(17, 0, 0); // 5 PM
if (now < businessStart || now >= businessEnd)
{
// If outside business hours, register a rule that effectively shows no data.
// "ReportKey" is assumed to be a field in the FinancialReports controller.
// The actual implementation of "1=2" or similar denial depends
// on how RegisterAccessControlRule translates it.
// This example shows the intent.
RegisterAccessControlRule("ReportKey", "1=2" /* or a specific denial mechanism */, AccessPermission.Allow, null);
}
}
}
- Why use it: Offers ultimate flexibility when declarative rules are insufficient.
- Considerations: Requires programming knowledge. Rules are embedded within compiled code, making them less visible from a pure configuration standpoint. There's a higher potential for introducing bugs. Changes require recompilation and deployment.
- View
Filter Expression - For Defining Business Views (Not Primarily for Security):
-
- Purpose: Use
Filter Expression
to create different pre-filtered perspectives or "business views" of data that the user is already authorized to see. This is not intended as a primary security mechanism, as these client-side or simple server-side filters can sometimes be bypassed or cleared by users with sufficient knowledge of the application's requests.
- Method: Set the
Filter Expression
property directly on individual view nodes (e.g., grid1
, editForm1
) within a data controller's XML definition. This typically involves a simple SQL WHERE
clause condition.
- Example: On an "Orders" page, you might offer several views:
-
- A default view (
grid1
) showing all orders the user is permitted to see (as determined by SACR or code rules).
- A view named
grid1OpenOrders
with its Filter Expression
set to Status = 'Open'
.
- Another view named
grid1RecentOrders
with Filter Expression
set to OrderDate >= DATEADD(month, -1, GETDATE())
. When a user selects the "Open Orders" view, they will see only open orders, but only those open orders that they were already authorized to see by the underlying SACR or code-based rules.
- Why use it: Provides user convenience for common data perspectives, improving usability.
- Considerations: Absolutely not a replacement for robust security. Applying the same security logic via filter expressions across many views leads to significant repetition and maintenance headaches.
Our Recommendation Summarized:
- For Security: Prioritize Static Access Control Rules (SACR).
- For Complex Security Exceptions: Use Dynamic (Code-Based) Access Control Rules.
- For User Convenience/Data Perspectives: Use View
Filter Expression on data already secured by SACR or code.
How SACR Works: Behind the Scenes (In Plain English)
You don't need to write or even look at C# or VB.NET code to effectively use Static Access Control Rules, as App Studio provides a complete visual interface. However, understanding the general process the framework follows can help you configure your rules more effectively and troubleshoot if needed.
This is the definition of the access rules created in the tutorial and saved to the ~/app/touch-settings.json
file of the application.
JSON
123456789101112131415161718192021222324252627{
"server": {
"accessControlRules": {
"rules": [
{
"triggerField": "LastName",
"where": "@BusinessRules_UserName",
"comment": "Employees can only view their own record.",
"enabled": true
},
{
"triggerField": "EmployeeLastName",
"where": "@BusinessRules_UserName",
"comment": "Restrict orders to those managed by the logged-in employee."
},
{
"triggerField": "CustomerID",
"where": "SELECT DISTINCT O.CustomerID\nFROM Orders O\nINNER JOIN Employees E ON O.EmployeeID = E.EmployeeID\nWHERE E.LastName = @BusinessRules_UserName \n",
"comment": "Show customers only if the logged-in employee has placed orders for them.",
"enabled": true,
"controller": "Customers"
}
],
"fullAccess": "Administrators"
}
}
}
Imagine a user opens a page in your application, say, a list of customer orders. Here's a simplified flow of how SACR comes into play:
- Request Arrives: The application receives the request to display orders.
- Framework Prepares: Before fetching any data from the database, the Code On Time framework gets ready to apply security.
- Reads
touch-settings.json: It looks into your application's touch-settings.json
file for the server.accessControlRules
section.
- Checks for "Full Access" Roles: The first thing it checks is the
fullAccess
property. If the currently logged-in user belongs to any role listed here (e.g., "Administrators"), the framework stops processing any further SACR rules for this user. They get to see all data (though standard controller permissions still apply).
- Iterates Through Your Defined Rules: If the user doesn't have "full access," the framework goes through the list of individual rules you've defined in the
rules
array. For each rule, it performs several checks:
-
- Is the Rule Enabled? Each rule has an
enabled
property (which defaults to true
). If you've set it to false
(perhaps for testing), the framework skips this rule.
- Does it Apply to this Specific Data Controller? Rules can optionally specify a
controller
property (using a text pattern called a regular expression). If this rule is meant only for, say, the "Products" controller, but the current request is for "Orders," this rule is skipped. If the controller
property is blank, the rule is considered potentially applicable to any controller.
- Is the "Trigger Field" Present? This is a key concept. Each rule defines a
triggerField
(e.g., EmployeeLastName
). The framework checks if this exact field name (case-insensitively) is actually part of the data being requested by the current view (e.g., the grid of orders). If the EmployeeLastName
field isn't being shown in that particular order view, then a rule triggered by EmployeeLastName
won't apply.
- Has This Trigger Field Already Been Handled? For any given data request to a controller, the framework will only apply one SACR rule per unique
triggerField
. It keeps track of trigger fields for which it has already found and processed a matching rule. If it encounters another rule later in your configuration that uses the same triggerField
(and all other conditions match), it will skip this subsequent rule. This means the order of your rules in
touch-settings.json is important if you have multiple rules that could potentially apply to the same triggerField
under different conditions (e.g., different role-based logic for the same field). The first one that fully matches takes precedence for that trigger.
- Does the User Meet the Role Requirements? If the rule has a
roles
property (a comma-separated string like "Managers, Supervisors"), the framework checks if the current user is a member of at least one of those roles. If roles are specified in the rule but the user isn't in any of them, the rule is skipped. If the rule has no roles specified, this check is passed for all users.
- Applying the Matched Rule's Logic: If a rule successfully passes all the above checks and is the first one to do so for its specific
triggerField
in the current context:
-
- The framework looks at the rule's
access
property. In App Studio, you configure this as the "Filter" property with choices like "Include If Match" (internally allow
) or "Exclude If Match" (internally deny
).
- It then takes the where property from your rule. In App Studio, this is determined by your selection in the "Equals" dropdown (which might set
where
to something like @BusinessRules_UserID
) or by the custom SQL
you enter into the "SQL" property if "Equals" is set to SQL
.
- The framework then constructs a SQL condition that will be added to the database query:
-
- If "Filter" is
Include If Match (allow)
: The condition will be something like YourTriggerFieldName IN (result of your 'where' expression)
. For example, if triggerField
is EmployeeID
and where
is @BusinessRules_UserID
, it becomes EmployeeID= CurrentUserIDValue
. If where
is a subquery like SELECT DepartmentID FROM UserDepartments WHERE UserID = @BusinessRules_UserID
, it becomes DepartmentID IN (SELECT DepartmentID FROM UserDepartments WHERE UserID = CurrentUserIDValue)
. The parameter will be present in the final SQL as-is and its value will be set by the framework automatically. The CurrentUserIDValue
is used for the explanation purposes only.
- If "Filter" is
Exclude If Match (deny)
: The condition will be YourTriggerFieldName NOT IN (result of your 'where' expression)
.
- Building the Final, Secure Query: The framework takes this generated SQL condition (or multiple conditions if different trigger fields in the view activated different rules) and intelligently combines them with
AND
into the main WHERE
clause of the SQL query it's building to fetch the data. It also merges these with any filters the user might have applied through the application's search bar or column filters.
- Database Executes the Filtered Query: Finally, this complete, secured SQL query is sent to your database. The database engine, which is highly optimized for this kind of work, efficiently filters the data and returns only the rows that the user is authorized to see according to your SACR rules.
This "database friendly" approach ensures that the security filtering is performed efficiently by the database itself, leading to good application performance. The key is that you define the intent of the security declaratively, and the framework handles the complex task of weaving it into the data access layer.
Conclusion: Secure, Simple, and Scalable
Static Access Control Rules (SACR) in Code On Time represent a significant step forward in simplifying and centralizing row-level security. By embracing a declarative model that leverages your existing SQL knowledge and integrates seamlessly with the unique data controller architecture of the platform, SACR makes security configuration more accessible, transparent, and maintainable.
The true power of SACR is amplified by App Studio. Its visual tools, instant feedback mechanisms like the "security shield" icon, contextual navigation actions, and simplified debugging capabilities empower developers to define, manage, and verify security rules with unprecedented ease and confidence.
While dynamic, code-based access control rules retain their vital role for handling highly specialized or "exotic" security requirements, SACR is poised to become the standard, go-to method for the vast majority of data access restrictions. This shift not only enhances developer productivity but also contributes to building more consistently secure and scalable applications. By making security easier to implement correctly, Code On Time with SACR helps you focus more on delivering business value, knowing your data is well-protected.#