In this video, we'll be focusing on the
implementation of authentication and authorization features within a Blazor
web application. Our first task involves the development of a user-friendly login page,
allowing users to authenticate themselves by entering their credentials. Additionally, we'll
delve into the establishment of permissions based on user roles. This ensures that users
can only access components and features for which they have been explicitly granted the
permission. So, let's delve into the details of this implementation. To begin, we'll incorporate the
necessary services in the program.cs class of our new Blazor web app project. I'm utilizing
the AddAuthentication method to register the essential Services required for authentication. For
the authentication mechanism, we'll be using cookie authentication by assigning CookieAuthenticationDefaults
dot authentication scheme as the default scheme. Subsequently, I'll use the AddCookie
method to configure various options such as assigning a custom name to the cookie for easier
identification. Additionally we'll designate the login path anticipating the creation of a login
page with this specified URL. In consideration of user experience, I typically set a MaxAge for
the cookie to facilitate automatic logout after a specific duration. Furthermore, an access-denied
page is being assigned to address scenarios where user attempt to access unauthorized Pages leading
to the creation of an error display page. Moving forward, we'll integrate Middlewares for both
authentication and authorization. I'm incorporating the authorization service through the use of
the AddAuthorization method. Lastly a crucial service is introduced using the AddCascading
AuthenticationState, responsible for efficiently passing the authentication State throughout the
application. I have just Incorporated database integration to our application, enabling the
retrieval of user account details from the SQL Server database. As we have previously covered the
details of the database integration in our earlier videos, I won't delve into extensive explanations
here. For those who interested in the code, it is available on our patreon page and you can find
the link in the video description. Within the app settings, I have specified the connection string
and introduced an entity named user account. The data folder houses the DbContext class. Let
me show you a quick look at the database in my SQL management studio. If you look into the
user account table, you'll observe two users. Each assigned different roles: Administrator
and User. Moving on, we'll proceed to develop the login page. In the pages folder, I'm creating
a new folder called 'Account' to organize Pages related to authentication and authorization. Our
first task is to add a new razor component called login in this specified folder. Before delving
into the development of the login page, we'll establish a view model to manage user input.
Inside the newly created view models folder, I'm creating a class named LoginViewModel. This
class will incorporate two properties: Username and password. To enhance user input validation,
I'll include the required attribute for both the properties along with custom error messages.
Within the login page, we'll declare the login view model object and utilize the supply
parameter from form attribute, as we'll be receiving the object property values from an edit
form. Next, let me provide the design for entering the credentials. To handle the form submission,
we'll create a method named 'Authenticate'. The form includes input text elements for both username
and password, accompanied by validation messages for enhanced user guidance. Additionally, a string
variable for error messages will be declared and the error message will be displayed just above the
login button. To facilitate user authentication, we require the HttpContext object, which can be
obtained as a CascadingParameter. Let's proceed with implementing the authenticate method. To
access the user account details from the database, we'll inject the DbContext into the component.
Initially, we fetch the user account by filtering with the username provided in the input text.
Subsequently, we check if the user account object is null, indicating the absence of a user account
with the provided username. We also verify if the provided password matches. In case of any invalid
input, we display an error message and exit the method. If both conditions are met, we proceed to
create a list of claims. The first claim holds the username, while the second one holds the user
role. Following this, a claims identity object is generated with the claims as the first parameter
and the authentication scheme used previously as the second parameter. We then create a claims
principal using the identity object. Finally the SignInAsync method is utilized to sign in
the principal, completing the user authentication process. Upon successful authentication, we can
redirect the user back to the homepage. To achieve this, we'll inject the navigation manager and
utilize the NavigateTo method for redirection. Additionally, let's configure the page URL to
align with the one assigned as the login path in the program.cs class. Ensuring consistency in
navigation. Moving forward, let's create the access denied page within the accounts folder. I'm adding a
razor component named AccessDenied to maintain consistency. I'll use the same URL as specified in
the dependency service options. The design of this page will be straightforward, displaying a message
such as "You don't have permission to access this page". Next, we'll create the logout page which will
be displayed when a user clicks the logout button. First, let's assign the page URL on this page. We'll
present a simple message confirming successful logout. In the code section, we obtain the HTTP
context object through cascading parameters. Moving on, we override the OnInitializedAync
method and make it asynchronous. Within this method, we check if the user is authenticated.
If yes, we proceed to sign out the user using the SignOutAsync method. To ensure components
are refreshed, we use the navigation manager to reload the page. Navigating the user to the same
page with the force load parameter enabled. Now to implement different behaviors in the application
based on the authentication status, let's start by making changes to the main layout. Within the
main layout, we'll incorporate the AuthorizeView to conditionally display login and logout buttons.
To simplify the code, we'll remove the namespace from the tag and import it. Considering the
need for this namespace in other Pages as well, we'll move it to imports.razor. Enabling
its use in any components. For users who are not authorized, we display a login button. On the other
hand for authorized users, we can present the logout button. In the NavMenu component as well, we'll
incorporate the AuthorizeView and Authorized tags. Additionally, roles will be assigned for the
AuthorizeView to control access. We'll move the counter page NavLink inside the Authorized tag. So
that it is accessible only to the users with the role, administrator or user. Subsequently,
another AuthorizeView is included specifying only the administrator role. The weather page NavLink
will be moved within this tag. Ensuring that the weather page can only be accessed by users with
administrator role. Moving on to the homepage, you'll notice that no render modes are assigned
and its currently utilizing static render mode. For a more in-depth understanding of render modes you
can refer to the Blazor Web App video, part of the Blazor tutorial playlist. In the homepage, our focus
is on demonstrating how AuthorizeView works with a static page. We'll place a welcoming message at
the top and beneath that display the login or logout option based on the authentication status.
Proceeding to the counter page, you'll observe that it is using InteractiveServerRenderMode.
Our goal here is to display a button exclusively for authenticated users. We will Implement an
onclick method named DisplayGreetingAlert. The purpose of this method is to showcase a
greeting message along with the username of the authenticated user. To fetch the username from
code, we need the AuthenticationState object which can be retrieved from cascading parameters. The
object is of type task of AuthenticationState and we can obtain the AuthenticationState by
awaiting it. Now we can create the message to be displayed by concatenating the username from
AuthenticationState to the message. To display an alert, we'll inject IJSRuntime and leverage
InvokeVoidAsync method. To ensure proper functionality of the implemented features, an important change
needs to be made in the routes.razor component. Instead of using RouteView, we should utilize
AuthorizeRouteView for the desired functionality. This adjustment is crucial for
the proper functioning of the authentication and authorization features in the application. While
our project implementation remains incomplete, a minor issue perist within our application that
needs attention. Let's proceed to run the project and test all functionalities. While testing, I'll
demonstrate the issue and provide a resolution to address it. On the homepage, you'll notice the
welcome message along with the the two login buttons. Let's attempt to login using admin
account. Upon successful login, the menu options become visible and the logout button replaces the
login button on the homepage. Moving to the counter page, clicking the greeting button triggers an
alert displaying the username. Furthermore, access to the weather page is granted. All functionalities
appear to be functioning correctly. Clicking on the logout button appropriately displays the logout
message. Now let's proceed to login again with the other user account. You'll observe that
the weather option is no longer visible in the menu. On the counter page, the greeting message
now correctly displays the new username. Let's delve into the developer options to inspect the
authorization cookie. In the cookie section of the application tab, you can find the cookie
labeled 'auth_token' with its expiration period. As a demonstration if I delete the cookie, you'll
observe that I'm automatically logged out from the application. Now let me demonstrate the issue.
I'll signin with the user account and you'll notice that the weather option is not available
in the menu. However, if I attempt to access it by entering the URL manually in the address bar,
you can see that I'm able to bypass the intended authorization checks. Now after completely
logging out, I'll attempt to manually enter the URL. Surprisingly I can access the counter
page and interact with its components without proper authentication. Furthermore, the weather
page is also accessible for an unauthenticated user presenting a security loophole. Let's explore
how we can address and resolve this vulnerability. To enforce restrictions, we need to implement them
within the component itself. Let's begin with the weather component. We can introduce an attribute
named 'Authorize' for the weather component. Similar to AuthorizeView, we can specify roles within this
attribute. For this demonstration, I'm assigning the administrator role to restrict access. Now let's
implement the same authorization restrictions in the counter page. In this case, we'll allow
access for both administrator and user roles. Let's proceed to test these changes, I'm attempting
to access the page without signing in with any users. You'll notice an automatic redirection to the
login page. Now if we try accessing the weather page directly via its URL, we once again find
ourselves redirected to the login page. Reinforcing the authentication requirement. Let's proceed
to login with the user account. This user however is granted access only to the counter page. Let's
attempt to access the weather page and there comes the access denied page which we designed. Here the
user is authenticated but don't have permission to access this page. This concludes our discussion
for now. For a more in-depth understanding of Blazor, make sure to explore our comprehensive
Blazor tutorial playlist. If you found this video helpful, remember to show your support by liking,
sharing and subscribing to our Channel. Thank You!