<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Brenden K</title>
    <description>The latest articles on DEV Community by Brenden K (@bkehren).</description>
    <link>https://dev.to/bkehren</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F569160%2Fd4335591-50db-489d-ad76-6a86cf3f28f1.jpeg</url>
      <title>DEV Community: Brenden K</title>
      <link>https://dev.to/bkehren</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bkehren"/>
    <language>en</language>
    <item>
      <title>Implementing Authentication in Kentico Xperience 13</title>
      <dc:creator>Brenden K</dc:creator>
      <pubDate>Mon, 18 Jul 2022 18:09:32 +0000</pubDate>
      <link>https://dev.to/bkehren/implementing-authentication-in-kentico-xperience-13-2140</link>
      <guid>https://dev.to/bkehren/implementing-authentication-in-kentico-xperience-13-2140</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;During the development phases of your projects, clients sometimes want their site secured so it cannot be viewed without a valid login. Using previous versions of &lt;a href="https://xperience.io/"&gt;Kentico Xperience&lt;/a&gt;, this was done with&amp;nbsp;a few button clicks and like magic, authentication was in force.&amp;nbsp; Using the newest and greatest .NET technology, it's a bit more effort.&amp;nbsp; The idea around this article is to help you implement authentication quickly and effortlessly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is a &lt;a href="https://github.com/bkehren/Kentico-Xperience-Authentication"&gt;GitHub repo&lt;/a&gt; with the supporting code you can check out with the code necessary to implement authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Solution
&lt;/h2&gt;

&lt;p&gt;If you're looking for a more complex implemention to use with, for example, a membership portal or e-commerce site, you'll want to take the basics you'll learn here and expand on them.&lt;/p&gt;

&lt;p&gt;We'll take this step by step. Along the way, you may find I've missed a step, have a syntax error, etc., if you find something like this, please send me a note or submit a pull request on &lt;a href="https://github.com/bkehren/Kentico-Xperience-Authentication/pulls"&gt;GitHub&lt;/a&gt;. Let's get started!&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need your own instance of Kentico Xperience with a connected database. This example is using Xperience version 13.0.77.&lt;/li&gt;
&lt;li&gt;For testing purposes, you can import the &lt;a href="https://github.com/bkehren/Kentico-Xperience-Authentication/tree/main/PageTypes"&gt;page types I've included&lt;/a&gt; or create your own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1 - Verify Your Site Settings
&lt;/h3&gt;

&lt;p&gt;Log into your Kentico Xperience instance and navigate to the &lt;strong&gt;Settings&lt;/strong&gt; application. In the Settings application navigate to the &lt;strong&gt;Security &amp;amp; Membership&lt;/strong&gt; section. In the Content section, verify the "Check page-level permissions" is set to "Secured areas".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9XTfu6aH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/content-permissions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9XTfu6aH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/content-permissions.png" alt="" width="616" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Add Pages to your Content Tree
&lt;/h3&gt;

&lt;p&gt;For this step you'll need some pages in your content tree. If you do not have any page types created, check out the 2 simple page types I've created in the &lt;a href="https://github.com/bkehren/Kentico-Xperience-Authentication/tree/main/PageTypes"&gt;GitHub repo&lt;/a&gt; that you can import into your project. Both page types are simple, they have a field called "PageName" and they have all the page type features enabled.&lt;/p&gt;

&lt;p&gt;I've added a few testing pages to my content tree.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UhOkmzoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-structure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UhOkmzoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-structure.png" alt="" width="301" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 - Secure a Section
&lt;/h3&gt;

&lt;p&gt;We'll be securing the /Page-2 section of the site. If you want secure the whole site, you'll just perform the below actions on the root of the site vs. the Page 2 page. Keep in mind, the settings you put on the parent page will replicate through the child pages automatically.&lt;/p&gt;

&lt;p&gt;Select the Page 2 page in the content tree, then select the General &amp;gt; Security tab on the editor side. Scroll to the bottom of the Security page and check Yes for Requires authentication and save the page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a8sVceFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-security-setting.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a8sVceFE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-security-setting.png" alt="" width="700" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon saving the page you will have immediately&amp;nbsp;secured that page and all it's child pages. However, if you were to navigate to that page,&amp;nbsp;you'd have a&amp;nbsp;very poor user&amp;nbsp;experience and receive an ugly 403 error.&lt;/p&gt;

&lt;p&gt;I had you do these&amp;nbsp;steps&amp;nbsp;before implementing any&amp;nbsp;code because&amp;nbsp;this is a very quick way to lock things down &lt;strong&gt;IF&lt;/strong&gt;&amp;nbsp;you have an immediate need.&amp;nbsp; The problem&amp;nbsp;is there's no graceful fallback to handle any of the errors, login, redirects, etc., so lets look at how we can get the front facing website&amp;nbsp;to work with what we just implemented.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4&amp;nbsp;- Implement the Code
&lt;/h3&gt;

&lt;p&gt;Let's take a look at the project structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X2OVQOof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-project-structure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X2OVQOof--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-project-structure.png" alt="" width="321" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The files of importance are the&amp;nbsp;following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/Controllers/AccountController.cs
/Models/Users/Account/SignInViewModel.cs
/Views/Account/PermissionDenied.cshtml
/Views/Account/SignIn.cshtml
/Views/Account/WaitingForApproval.cshtml
/Views/Shared/\_SignInLayout.cshtml
/StartUp.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The files I mention above have the necessary code needed to implement security.&amp;nbsp; The project in GitHub has everything needed to get an example site, with authentication, up and running in less than 30 minutes.&amp;nbsp;&amp;nbsp;You will most likely not need all the extra files, but they are there for you to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4A - Implement the Account Controller
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AccountController : Controller
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Take a look at the &lt;strong&gt;/Controllers/AccountController.cs&lt;/strong&gt; file. This file has a few optional items in it but for the most part it can be implemented line for line.&amp;nbsp; You'll notice I've commented out all the code in this file and subsequent files that enable the "remember me" functionality.&amp;nbsp; If you wish to use this functionality, please read the comments and update the code accordingly.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4B - Implement the SignInViewModel
&lt;/h4&gt;

&lt;p&gt;As I mentioned before, the "Remember Me" functionality is commented out so if you're interested in that functionality, uncomment it in these files as well as the AccountController file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Required(ErrorMessage = "Please enter a user name")]
[Display(Name = "User name")]
[MaxLength(100, ErrorMessage = "The User name cannot be longer than 100 characters.")]
public string UserName { get; set; }

[DataType(DataType.Password)]
[Display(Name = "Password")]
[MaxLength(100, ErrorMessage = "The password cannot be longer than 100 characters.")]
public string Password { get; set; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4C - Implement the Views
&lt;/h4&gt;

&lt;p&gt;There are 4 views you'll need to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sign in layout view&lt;/strong&gt; - this holds a stripped down view of the _Layout.cshtml file that is used for all the "authentication" views.&amp;nbsp; The following 3 views will inherit this view.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sign in view&lt;/strong&gt; - this is the form the user will fill out to log in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Permission denied view&lt;/strong&gt; - this has a simple message to the user stating they cannot access the page, most likely due to roles that were implemented (this is another blog post).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Waiting for approval view&lt;/strong&gt; - this view displays a message to the user stating they have not been approved by the admin yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll notice below were using a pretty simple Bootstrap 5 implementation for the form and throughout the rest of the site.&amp;nbsp; One very important piece which caused me several hours of headache was the &lt;code&gt;asp-route-returnurl&lt;/code&gt; attribute and value on the Sign In view.&amp;nbsp; If you do not include this, your users will not be redirected back to where they were trying to go.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;h2&amp;gt;Sign in&amp;lt;/h2&amp;gt;
&amp;lt;div asp-validation-summary="ModelOnly"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;span&amp;gt;Please correct the following errors&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;form asp-controller="Account" asp-action="SignIn" method="post" class="row g-3" asp-route-returnUrl="@Context.Request.Query["ReturnUrl"]"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div class="col-12"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;label asp-for="UserName" class="form-label"&amp;gt;&amp;lt;/label&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;input asp-for="UserName" class="form-control" required /&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;span asp-validation-for="UserName" class="text-danger"&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;

&amp;nbsp; &amp;nbsp; &amp;lt;div class="col-12"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;label asp-for="Password" class="form-label"&amp;gt;&amp;lt;/label&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;input asp-for="Password" class="form-control" required /&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;span asp-validation-for="Password" class="text-danger"&amp;gt;&amp;lt;/span&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;
&amp;nbsp; &amp;nbsp; @* Enable if you want the "remember me" feature to work *@
&amp;nbsp; &amp;nbsp; @*&amp;lt;div class="col-12"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;span class="logon-remember-me-checkbox checkbox"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @Html.EditorFor(model =&amp;gt; model.RememberMe) @Html.LabelFor(model =&amp;gt; model.RememberMe)
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/span&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;*@
&amp;nbsp; &amp;nbsp; &amp;lt;div class="col-12"&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;input type="submit" value="Sign in" class="btn btn-primary" /&amp;gt;
&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4D&amp;nbsp;- Implement the&amp;nbsp;Startup.cs Code
&lt;/h4&gt;

&lt;p&gt;The following method is the main area of importance.&amp;nbsp; There are a few other minor areas and you'll see them as you check out the code file, but this method is the most important piece you'll want to make sure is implemented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/// &amp;lt;summary&amp;gt;
/// Method used to configure authentation for a Kentico Xperience site
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="services"&amp;gt;&amp;lt;/param&amp;gt;
private static void ConfigureMembershipServices(IServiceCollection services)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method has all the necessary pieces you'll need to properly implement a "quick" authentication option within your site.&amp;nbsp; Again, these are the minimum pieces needed.&amp;nbsp; If you want to enable more features or functionalty, I'd suggest reading the &lt;a href="https://docs.xperience.io/managing-users/user-registration-and-authentication"&gt;Kentico Xperience documentation&lt;/a&gt; or checking out the &lt;a href="https://github.com/Kentico/xperience-training-13"&gt;Kentico Xperience Training&amp;nbsp;sample site&lt;/a&gt;&amp;nbsp;on GitHub (this code repo cooresponds with Kentico Xperience Developer Training).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5 - Implement a Sign Out Button
&lt;/h3&gt;

&lt;p&gt;While I didn't mention this file in a previous step, it is worth noting if we're allowing a user to sign in, we should also allow them to sign out.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/bkehren/Kentico-Xperience-Authentication/blob/main/KXAuthentication/Components/ViewComponents/MasterPage/Footer/Default.cshtml"&gt;Footer view&lt;/a&gt;.&amp;nbsp; At the bottom of the page you'll find a very simple logical statement with a form and a button inside it.&amp;nbsp; This will only show if the user is authenticated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@if (User.Identity.IsAuthenticated)
{
&amp;nbsp; &amp;nbsp; @\* Give the user a signout button if signed in \*@
&amp;nbsp; &amp;nbsp; @using (Html.BeginForm("SignOut", "Account", FormMethod.Post))
&amp;nbsp; &amp;nbsp; {
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; @Html.AntiForgeryToken()
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;button type="submit" class="btn btn-link"&amp;gt;Sign Out&amp;lt;/button&amp;gt;
&amp;nbsp; &amp;nbsp; }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Putting It All Together
&lt;/h3&gt;

&lt;p&gt;Below are a few screenshots of the basic site and how it works.&lt;/p&gt;

&lt;p&gt;Non-Secured Page:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZaVVsLgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZaVVsLgy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-1.png" alt="" width="531" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Trying to access a secured page, forcing login:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--geO5NKrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-2-1-login.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--geO5NKrM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-page-2-1-login.png" alt="" width="676" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in, you have access to the "secure" content:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B5K7UZ37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-secured-page-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B5K7UZ37--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.kehrendev.com/KehrenDev/media/blog/bk/kx-secured-page-1.png" alt="" width="551" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a very simplistic implementation.&amp;nbsp; It does NOT:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;implement roles,&lt;/li&gt;
&lt;li&gt;implement any kind of registration,&lt;/li&gt;
&lt;li&gt;implement any kind of password retrieval or resetting abilities,&lt;/li&gt;
&lt;li&gt;implement any kind of area specific permissions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What it does do is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;requires a user to be created in the Kentico Xperience User's application,&lt;/li&gt;
&lt;li&gt;allows that user to log into the public site,&lt;/li&gt;
&lt;li&gt;allows a user to access pages that require authentication,&lt;/li&gt;
&lt;li&gt;allows a user to log out if they are logged in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the event you no longer need authentication on your site, you can&amp;nbsp;set the security settings for that page or section of pages to &lt;strong&gt;Requires authentication = NO or Inherit (NO)&lt;/strong&gt;.&amp;nbsp; There's no real issue leaving the code in place either except that all the "/Account" pages will be accessible.&lt;/p&gt;

&lt;p&gt;And that's it!&amp;nbsp; While it may seem like a daunting task to get done, you should be able to get this example up an running within 30 minutes even if you have to install&amp;nbsp;a new instance of Kentico Xperience.&lt;/p&gt;

&lt;p&gt;Looking forward to seeing your comments and improvements to this on GitHub!&lt;/p&gt;

&lt;p&gt;Best of luck and Happy Coding!&lt;/p&gt;

</description>
      <category>xperience</category>
      <category>kentico</category>
      <category>authentication</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
