Permission Checking - HL Vanilla Community
<main> <article class="userContent"> <div class="embedExternal embedImage display-large float-none"> <div class="embedExternal-content"> <a class="embedImage-link" href="https://us.v-cdn.net/6030677/uploads/6XGCFPDAIGEL/microsoftteams-image-288-29.png" rel="nofollow noreferrer noopener ugc" target="_blank"> <img class="embedImage-img" src="https://us.v-cdn.net/6030677/uploads/6XGCFPDAIGEL/microsoftteams-image-288-29.png" alt="MicrosoftTeams-image (8).png" height="108" width="1356" loading="lazy" data-display-size="large" data-float="none"></img></a> </div> </div> <p>Vanilla uses permissions to restrict access to particular content, options, or workflows. There are a number of functions built into the framework to do this efficiently. We eschew role-detection as a means of access control.</p><p>For example, we would never check to make sure someone was in a role named Moderator before granting access to an option, we would check a permission like <code class="code codeInline" spellcheck="false" tabindex="0">Garden.Moderation.Manage</code>.</p><h2 data-id="naming-permissions">Naming Permissions</h2><p>We use the same dot notation syntax for permissions as we do for config settings. A typical scheme would be: <code class="code codeInline" spellcheck="false" tabindex="0">Namespace.Keyword.Action</code>.</p><p>For instance, look at <code class="code codeInline" spellcheck="false" tabindex="0">Vanilla.Discussions.Add</code>. This permissions is registered by the Vanilla application, is related to discussions, and is specifically for adding.</p><p>For the Namespace (first dot tier), use the slug name of your addon. The <code class="code codeInline" spellcheck="false" tabindex="0">Plugins</code> namespace is deprecated.</p><p>The Keyword (second dot tier) should be the most concise description possible of the part of the addon it governs.</p><p>Whenever possible, use one of the following as your Action (third dot tier):</p><ul><li>Add</li><li>Edit</li><li>View</li><li>Manage</li><li>Delete</li></ul><p>Other action names are avoided and may be renamed or refactored out of the framework in the future. However, they are not forbidden and never will be.</p><h2 data-id="using-permissions">Using Permissions</h2><p>There are two basic ways to check a permission. One is to use a true/false conditional, typically to <code class="code codeInline" spellcheck="false" tabindex="0">checkPermission()</code> in an <code class="code codeInline" spellcheck="false" tabindex="0">if</code> statement:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">if (checkPermission('Permission.Name')) { // Do something special } </pre><p>The other is to wholesale block execution by a call to <code class="code codeInline" spellcheck="false" tabindex="0">Gdn::session()->permission()</code>. This method automatically triggers a permission exception:</p><pre class="code codeBlock" spellcheck="false" tabindex="0">public function Index() { Gdn::session()->permission('Permission.Name'); // Do priviliged things safely now } </pre><p>Typically we don’t use the first convention to trigger a permission exception manually because the second will cover it.</p><h2 data-id="multiple-permissions">Multiple Permissions</h2><p>You can use either method above to check multiple permissions by passing an array of permission names as the first parameter.</p><p>By default, it will require ALL permissions named to pass. If you pass a second parameter of <code class="code codeInline" spellcheck="false" tabindex="0">false</code>, then only ONE of the permissions is needed to pass.</p><p>You may find additional permission checks in Vanilla for permission names that do not appear in the Dashboard using this style: a normal permission name is passed in an array along with an “invisible” one. This is to allow plugins to define the additional permissions for more granular checks if needed.</p><h2 data-id="the-owner-flag">The Owner Flag</h2><p>The forum owner’s account (the one you create when installing Vanilla) gets a special flag set on it. This is accomplished by setting the <code class="code codeInline" spellcheck="false" tabindex="0">Admin</code> column equal to <code class="code codeInline" spellcheck="false" tabindex="0">1</code> in the <code class="code codeInline" spellcheck="false" tabindex="0">User</code> table.</p><p>Accounts with this flag set bypass all permission checks. <code class="code codeInline" spellcheck="false" tabindex="0">checkPermission</code> will always return <code class="code codeInline" spellcheck="false" tabindex="0">true</code> and no permission exception will ever be thrown for it. It will do this regardless of any role assignment.</p><p>For this reason, it is extremely important to test your addons with a non-owner account to see your permission checks in action.</p><h2 data-id="the-system-flag">The System Flag</h2><p>The System account is generated for general use by addons and cases where content must be generated by the forum. This account is designated by setting the <code class="code codeInline" spellcheck="false" tabindex="0">Admin</code> column equal to <code class="code codeInline" spellcheck="false" tabindex="0">2</code> in the <code class="code codeInline" spellcheck="false" tabindex="0">User</code> table.</p><p>This grants the same privileges as the Owner flag, and protects the account from deletion or banning.</p><h2 data-id="reversed-permission">Reversed Permission</h2><p>A special case in the framework is the <code class="code codeInline" spellcheck="false" tabindex="0">Vanilla.Approval.Require</code> permission. It is checked with the <code class="code codeInline" spellcheck="false" tabindex="0">checkRequirement</code> function. A <code class="code codeInline" spellcheck="false" tabindex="0">true</code> result means their content must go to the Moderation queue for approval. Therefore, a <code class="code codeInline" spellcheck="false" tabindex="0">true</code> result actually grants you <em>less</em> permission. We don’t generally recommend using this construct.</p> </article> </main>