#13 Main Navigation (Authentication)
Saturday, January 12, 2019
In this article we will focus on adding the authentication links. For this project that includes the ability for the user to register and login. If they are authenticated they will then have the ability to visit their account page and to logout. In the case of logging out we will use a form and see how to style it to look like all of the other links as well as how to include the anti-forgery token when creating a reusable variable as we have been doing.
Parts
- Part 29: Offset Pager Urls
- Part 28: Offset Pager Start
- Part 27: Mock Context Builder
- Part 26: Mock Repository
- Part 25: Mock Async
- Part 24: Picture Tag Helper
- Part 23: Img DPR Tag Helper
- Part 22: Img Responsive Tag Helper
- Part 21: Img Optimized Display
- Part 20: Img Optimization
- Part 19: Img Lazy Loading
- Part 18: Img Responsive
- Part 17: Bottom Nav
- Part 16: Main Nav Cookie
- Part 15: Main Nav Mobile
- Part 14: Main Nav Search
- Part 13: Main Nav Auth
- Part 12: Main Nav Anchors
- Part 11: Main Nav Logo
- Part 10: Search Results
- Part 9: Search Manager
- Part 8: Search Start
- Part 7: Seeding the Database
- Part 6: Domain Database
- Part 5: Emailing Exceptions
- Part 4: Mailkit
- Part 3: View Renderer
- Part 2: Upgrade to 2.1
- Part 1: Quick Start
More Icons
- WebUi
- Source
- main.site.ts
- Source
For our authentication links I want to use a few more icons so we will start by adding them to our library (a).
main.site.ts
...
import { faEdit } from "@fortawesome/free-solid-svg-icons/faEdit";
import { faSignInAlt } from "@fortawesome/free-solid-svg-icons/faSignInAlt";
import { faSignOutAlt } from "@fortawesome/free-solid-svg-icons/faSignOutAlt";
import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
library.add(
...
faEdit,
faSignInAlt,
faSignOutAlt,
faUser,
);
...
Adding more links
- WebUi
- Pages
- Shared
- _MainNav.cshtml
- Shared
- Pages
Now that we have some more icons it is time to use a couple of them. Since we want to use some icons
with these links we will add a LinkIcon
func and modify the
LinkText
func. With that change done we need to update the
Articles
and Applications
and add the Login
and Register
(b).
_MainNav.cshtml
...
@{
...
var LinkIcon = new Func<string, string>((icon) => $"<i class=\"fas fa-{icon} link-icon\"></i>");
var LinkText = new Func<..., string>((..., icon) => $"<div class=\"...\">{icon}<span>...</span></div>");
...
var Articles = Html.Raw(Li(Anchor(..., LinkText(..., ""))));
var Applications = Html.Raw(Li(Anchor(..., LinkText(..., ""))));
...
var Login = Html.Raw(Li(Anchor("/identity/login", LinkText("Login", LinkIcon("sign-in-alt")))));
var Register = Html.Raw(Li(Anchor("/identity/register", LinkText("Register", LinkIcon("edit")))));
}
<header>
<nav>
...
<div class="authentication">
<ul>
@Register
@Login
</ul>
</div>
</nav>
</header>
Styling the authentication list elements
- WebUi
- Source
- components
- main-nav
- main-nav.component.scss
- main-nav
- components
- Source
Now it is time to add just a little bit of styling and set the grid area of our authentication links (c).
main-nav.component.scss
...
header {
...
grid-template-areas: "... authentication";
grid-template-columns: auto auto auto;
...
@include media-gt($mobile-break-width) {
grid-template-areas: "... authentication";
grid-template-columns: ... auto;
}
...
.authentication {
grid-area: authentication;
display: none;
@include media-gt($mobile-break-width) {
display: block;
}
.link-icon {
margin-right: 0.25em;
}
}
}
What if we are authenticated?
- WebUi
- Pages
- Shared
- _MainNav.cshtml
- Shared
- Pages
We have taken care of being able to register and login but we need a couple more links if the
user is already authenticated. We will start by adding a Account
func just like all of the others and we will hard code in a form for allowing the user to logout
temporarily (d).
_MainNav.cshtml
...
@{
...
var isAuthenticated = !User.Identity.IsAuthenticated;
...
var Account = Html.Raw(Li(Anchor("/identity/account", LinkText("Account", LinkIcon("user")))));
...
}
<header>
<nav class="main-navigation">
...
<div class="authentication">
<ul>
@if (isAuthenticated)
{
@Account
<form action="/identity/logout" method="post">
@Html.AntiForgeryToken()
<button type="submit">
<i class="fas fa-sign-out-alt link-icon"></i>
<span>Logout</span>
</button>
</form>
}
else
{
@Register
@Login
}
</ul>
</div>
</nav>
</header>
Style the form
- WebUi
- Source
- components
- main-nav
- main-nav.component.scss
- main-nav
- components
- Source
Now that we have the form in place for logging out I would like to style it to look like all of the other links (e).
main-nav.component.scss
...
$action-color: #0984e3 !default;
...
header {
.authentication {
...
form {
display: flex;
align-items: center;
height: 100%;
button {
background: none;
border: none;
color: $navigation-anchor-color;
height: 100%;
@include padding(null em(10px));
cursor: pointer;
font-weight: 400;
&:hover {
background: none;
color: $action-color;
}
}
}
}
}
Hard coding is bad
- WebUi
- Pages
- Shared
- _MainNav.cshtml
- Shared
- Pages
As I have said previously the reason we are approaching our main navigation they way we are is so that we can define our links once and add them to the markup as many times as we like at any place we like. To stick with this approach we need to handle the form that we previously added. Since the only other form we will use is for the search functionality and it will only be located in one place we will not create a separate form func (f).
_MainNav.cshtml
@using System.IO
@using System.Text.Encodings.Web
...
@{
...
var writer = new StringWriter();
Html.AntiForgeryToken().WriteTo(writer, HtmlEncoder.Default);
var antiForgeryToken = writer.ToString();
...
var Logout = Html.Raw($"<form action=\"/identity/logout\" method=\"post\">{antiForgeryToken}<button type=\"submit\">{LinkIcon("sign-out")}<span>Logout</span></button></form>");
}
<header>
<nav class="main-navigation">
...
<div class="authentication">
<ul>
@if (isAuthenticated)
{
...
@Logout
}
else
{
...
}
</ul>
</div>
</nav>
</header>
Redirecting the user
- WebUi
- Pages
- Shared
- _MainNav.cshtml
- Shared
- Pages
The last thing we want to accomplish in this article is to have the ability to redirect the user back to whatever page they were viewing when they decide to either login or register (g).
_MainNav.cshtml
@using System.Net
...
@{
...
var redirectUrl = "/";
var path = Context.Request.Path;
if (path.HasValue && path.Value.Contains("error") == false && path.Value.Contains("identity") == false)
{
redirectUrl = path.Value;
}
var redirectQueryString = $"?redirectUrl={WebUtility.UrlEncode(redirectUrl)}";
var Login = Html.Raw(Li(Anchor($"/identity/login{redirectQueryString}", ...)));
var Register = Html.Raw(Li(Anchor($"/identity/register{redirectQueryString}", ...)));
}
...