Security
Overview
Web security is a very important topic for anyone who wants to keep their data safe. Smartstore offers ways to restrict access to data:
An extensible, hierarchically organized permissions system, where permissions are assigned to customer roles, which are then assigned to customers.
Customer roles (including assigned permissions) can automatically be assigned to customers by rule sets.
IAclRestricted marks an entity with restricted access rights. Only customers assigned to specific customer groups can see or access it.
Further security tools available are:
Anti-forgery token
Captcha
Honeypot
Permissions tree
Permissions are organized hierarchically in the form of a tree. A permission is granted when it has either granted itself or one of its parent permissions. The same applies to a permission that is explicitly not permitted. In this way, entire groups of permissions can be activated via a parent permission, where child permissions inherit from any ancestor. Therefore, a permission can have four statuses:
Allow
Disallow
Inherited allow
Inherited disallow

Authorization
Use the IPermissionService to check whether a given permission is granted to a customer. It expects strings as the name of the permission to be checked. Several constants are provided through the Permissions
class for this purpose.
await _permissionService.AuthorizeAsync(Permissions.System.ScheduleTask.Execute);
Action methods use the PermissionAttribute
instead of IPermissionService.
[Permission(Permissions.Catalog.Product.Read)]
public async Task<IActionResult> Edit(int id)
{
//...
}
Use the NeverAuthorizeAttribute
when the access to the requested endpoint is always permitted. For instance, the action method of the login page is decorated with this attribute.
An AccessDeniedException
is thrown when the permission is not granted. In case of an AJAX request, a message notification is shown, and an alert is returned if a HTML response is expected, or a JSON object otherwise.
Add custom permissions
The permission system can be extended to include custom permissions using the IPermissionProvider. See the DevToolsPermissionProvider example. It is recommended to use singular for permission names and define a root permission Self that doesn't contain any dots by convention:
public const string Self = "megasearch";
The localization is done via string resources and by convention. The string resource key is Permissions.DisplayName.<PermissionName>
for the core and Modules.Permissions.DisplayName.<PermissionName>
for modules. In most cases only the root permission Self is localized because other permissions are already localized by the core like read, update, execute etc. See PermissionService._displayNameResourceKeys
for a complete list.
Access control list (ACL)
An entity supports restricted access rights when it implements IAclRestricted. It allows limiting an entity to certain customer roles. Only customers who are assigned to one of the associated customer roles can see the product, the category, the menu item, etc.
Use IAclService to check whether the customer has the right to access an entity. If you only want to load those entities from the database the customer has access to, use the ApplyAclFilter
extension method.
Use IAclService.ApplyAclMappingsAsync
when you want to modify the access rights of a customer to an entity. This is typically done when the entity is updated on its edit page.
Protection tools
Anti-Forgery token
To help prevent CSRF attacks, ASP.NET Core uses anti-forgery tokens, also called request verification tokens. Such a token is automatically created if the HTML form tag uses at least one asp-* attribute and the form is processed by the ASP.NET Core TagHelper
accordingly.
<form asp-action="Configure">
In all other cases, Html.AntiForgeryToken()
must be explicitly called inside the view for the token to be rendered.
Data grids also create the token automatically but only if the property allowEdit or allowRowSelection is true. Only in these cases the data grid has its own HTML form:
<datagrid id="myentity-grid" allow-row-selection="true" allow-edit="true">
@* ... *@
</datagrid>
Otherwise the IgnoreAntiforgeryTokenAttribute
must be used on the server side to suppress the validation of the token and avoid errors due to a missing token.
For AJAX operations via smartstore.ajax.js or jQuery the token is also generated automatically. Only if a HTML form is created from scratch, the token must be included as well:
var form = '<form id="MyHtmlForm" action="' + $(this).data('url') + '" method="post">';
form += '<input type="hidden" name="__RequestVerificationToken" value="@Html.GetAntiforgeryToken()">';
form += '</form>';
$('body').append(form);
$('#MyHtmlForm').submit();
Captcha
Decorate an action method with the ValidateCaptchaAttribute
to prevent malicious software from accessing your endpoint. The attribute uses the widely used Google reCAPTCHA for protection. CaptchaTagHelper
renders the Google widget in your view.
<captcha sm-enabled="Model.DisplayCaptcha" class="form-group" />
Honeypot
"Honeypots" can be used to prevent robots from posting or manipulating HTML forms. The ValidateHoneypotAttribute
redirects back to the current page if an HTML form has been modified by a bot. HoneypotTagHelper
renders the required form element in your view.
<honeypot sm-enabled="true" />
Others
In addition to those already mentioned, there are a few other attributes with similar access-restricting functions.
AuthorizeAdmin
*
Checks whether the current user has the permission to access the administration backend.
AuthorizeShopAccess
Checks whether the current user has the permission to access the shop.
DisallowRobot
Disallows robots to access an endpoint.
RequireSsl
A marker filter indicating that the current request should be received over HTTPS (if the policies allow this).
ValidateAdminIpAddress
*
Validates the IP address of the user requesting access and match it against a list of allowed IP addresses.
* if your controller inherits from AdminController
, this attribute is automatically set and your controller is protected accordingly.
Last updated
Was this helpful?