Okay.
Our next step in this training course is to think about these login and register buttons, and also
the fact that we've got an area of our application that we only want authorized users to be able to
access, as in people who have logged in to our application.
And to do that, we're going to make use of Aspnet identity.
Now, since dotnet eight, there's been a specific usage of this that's designed to secure a web API
backend for Spars, a single page application, which is what we're building on our react side of things.
So we'll take a look at the documentation for this.
And what this gives us is effectively a lot of pre-built code.
And when it does come to identity, we can create a custom version of and use identity.
We can create our own user store.
We can create our own password system, but that comes with a bit of work to configure it anyway.
And it comes with a lot of risk because there's quite a lot involved in securing something to protect
our web application from the bad people on the internet.
And it's better not to do this ourselves.
And it's better to use something from someone like Microsoft who do update it, who do devote resources
to creating the code for this to make it as secure as possible.
And the way that we're going to do this, we're going to have our dotnet application effectively being
the identity store and checking the passwords to allow our users to log in.
And as far as handling authentication ourselves in our own application and not offloading it to a third
party like Azure, like one of the many other identity providers out there, this is probably as good
as we can get for our application if we want to do everything within our application.
So we're going to take a look at configuring this inside our application.
And this has been available to us since dotnet eight.
And we're going to use something referred to as the identity endpoints.
And effectively, if we take a look at the documentation here, then it gives us, once we configure
this, all of these different endpoints with not too much code.
So we've got things like a register endpoint a login endpoint a refresh endpoint.
If we were using JWT tokens we could refresh the token.
We've got to confirm email, resend confirmation email, forgot password, reset password and so on
and so on.
So we get all of this functionality without needing to write the code ourselves.
Is it 100% perfect for us?
No, probably not, and we'll need to tweak a few things, but it's good enough for our usage and certainly
good enough from a security perspective for what we're going to demonstrate here.
So we're going to go and set this up.
And to do that, we're going to install a package into our project for Aspnet identity.
So we're going to do this on the API first of all.
So we're going to go back to this solution Explorer view.
But we'll open up new gates.
First of all, and we're going to search for the Microsoft dot ASP.
Net core dot identity.
And we need the Identity Entity Framework core, because this package will allow us to create some tables
in our database related to identity.
So we'll go ahead and add this into our API keys proj file, which effectively adds this package into
our project.
And the latest one available because we're on net nine is of course dot net nine.
So let's go to our entities first of all.
And we're going to create a new file.
And it's going to be a class and we'll call it user.
Now this particular class we're going to derive from an identity entity.
So we'll use a colon.
And we're going to derive from identity user.
Now we're not going to add any additional properties for this.
because if we do, go and take a look at the code for the identity user class, then what this gives
us, it gives us an ID, which is a type of string.
It uses a guide to a string, a security stamp, a username, and all of these other properties.
Normalized username.
Email.
Normalized email.
Email.
Confirmed password.
Hash.
So we do ask the user for a password, but we store it in our database as a password hash.
So even if our database does get compromised, then hashing a password is a one way operation.
And I'm not saying that's impossible to crack, but it does take time and computing resources to do
so.
So we don't store our password in clear text.
We use this approach and we're not going to tweak anything like how secure is our password hash.
There is a presumption I'm making here that what we get from Microsoft doesn't need to be made secure.
It is secure, and anything we change has the potential to make it less secure than it was given to
us.
So we've got all of this stuff just by adding or deriving from the identity user class.
Next we're going to go to our store context and open up the store context class.
And inside here currently we're deriving from DB context, but instead we're going to derive from the
identity Dbcontext.
And we're going to specify a type in here of the user entity that we have just created.
So this effectively is part of the configuration that we write.
That's going to give us all of our identity related tables.
We don't need to do anything else inside here.
Or I say we don't need to, but we are going to.
If we just wanted users and nothing else, this would be sufficient.
But what we'll also take the opportunity to do is we're going to create a couple of roles inside our
database so that we can have an admin user.
And I'm going to show a different approach to seeding data here.
And we're going to use the configuration to do so, rather than creating a seed class or adding this
functionality into our seed class.
So if we just start typing override here, press space and start typing on, then we get access to the
on model creating.
And.
This builder argument will make use of to add some data inside our database.
So we'll use builder.
And then we can specify entity.
Which entity do we want to use this on.
And another entity that we get with identity is the identity role which we get from Microsoft Aspnet
identity.
And we'll add parentheses.
And below this we'll add period and has data.
And we can add effectively some data into our migration.
So I'll open parentheses.
And inside the parentheses we'll have a new identity.
Role.
And we'll open curly brackets will give it a name equal to member.
And we'll give it a normalized name and normalize.
Names in this world are all in capitals.
So remember and I'll just copy this down I'll just add a comma.
Copy that down.
And the next one will be admin.
And the normalized name will be admin as well.
And what I'll also do for this example.
Now these are going to be strings of for the ID of these just like it is for the user.
But if we don't specify this then Identity or entity framework will create a new ID for us.
But every time we add a new migration it does something with these.
So what I'll do actually is I'm just going to go out to a grid generator and just use the top link,
the free online generator tool for grid generator.
How many guys do I want?
I want two and if I generate some guides then let's just use these as the IDs inside here.
So just do the same trick that I did there just to get some goods, and it'll just make sure that these
are static and not dynamic.
Every time we add a new migration where our roles get removed and then replaced, and I'll do the same
for the second one as well, I'll set its ID to be the other guid I generated here.
And paste that in and it will just stop some weird behavior with Entity Framework when we create new
migrations based on what we've done here, and just a small update based on something that's come up
in a Q&A from a student that's using Net ten in dotnet ten or Entity Framework ten.
More specifically, then this is not enough because the ID field is dynamically generated if we don't
supply it.
So we do have a hard coded Guid inside there.
That's a string.
That's fine.
But there's another property inside here also dynamically generated the concurrency stamp.
And we also need to hard code this as well.
So just put in a hard coded value here for both the member and the admin, so that this is no longer
dynamically generated.
It is a guide, but it is a string property.
So we can just set member and admin inside here like this.
That means it's not going to be dynamically generated if you don't have this and you're on Entity Framework
Core ten, then it will definitely cause your application to throw an exception when you restart it,
or when you try and start your app and apply this migration.
So please ensure that you have hard coded values for any values that can be dynamically generated,
such as the ID and the concurrency stamp.
Prior to Net ten wasn't a big issue.
It still caused you some weirdness with migrations, but it wouldn't stop your app from working.
But now in Entity Framework ten, it does stop the app from working, so that will fix that issue.
So that's what we need for our two different roles.
And next we'll take a look at the next part of the configuration we need to set up in the program class.