Okay, now that we've got our configuration in place, we're going to see a couple of users.
We're setting up roles.
We're going to be creating new tables in our database.
First of all, let's create the migration that we need to enable us to do that.
And we'll go back to our API.
And we'll definitely need to stop our API for what we're about to do here.
I don't think anything that I see inside here is genuinely a problem.
It's just hot reloads trying to do its thing.
But please do stop your API and we will.
After we've stopped that, we'll add a new migration.
So we need dotnet EF migrations add.
And I'm just going to say identity added as the migration name and press return.
And this should go ahead and create the migration for us.
That includes the identity tables.
So let's go and take a look at what this has given us.
And if I open up the data folder inside our migrations, we've now got our identity migration.
And inside here we're going to create a bunch of tables.
So we're going to create a table for our roles.
And we have a couple of roles that are going to be added as part of this.
So we can see the name and normalized name that we added in our configuration for seeding those roles
in.
We're also going to have a users table with user related columns, things like username, email, email
confirmed, etc. we're also going to have some ASP.Net role claims.
We're going to get some tables in here that we do not need nor will we touch.
They're not going to do any harm.
They're just going to sit in our database.
This would be one of those examples we're not actually going to use or need.
And then we've got our ASP.Net user claims again same thing.
We won't look at that table ASP.Net users logins another table that will neither need nor look at.
And then we've got our user roles, which of course we will do because each user is going to be placed
in one or more roles.
And then we've got things like user tokens and Evelyn that this is the data that we're creating when
we apply this migration.
It's going to create these two roles inside here.
And could we have used this same technique?
You might be thinking for our users.
Well no not really because we need to use the user manager functionality so that our password that we
provide gets hashed effectively.
So it's not stored in our database in clear text.
If we were to attempt to create a user in this way, we'd definitely have problems with a password.
So it's best to use the user manager to add those users in that way.
So that's our migration, and what we should be able to do now is go back to our terminal, and we will
just use dotnet watch to apply that migration and see the additional data into our database.
So I'll use dotnet watch and see what happens.
And it looks like I've got an error here actually.
So let's see what this is about.
And quite a nasty looking error here and is telling us unique constraint failed for normalized username.
I've got this horrible feeling that copying and pasting continues to be a very bad idea, because if
I've got a duplicate username, then my suspicion is that in my DB initializer class, did I forget
to update the username?
Inside here I did something I forgot to update user and swap that for admin.
So that's the reason for the error I'm getting here.
And I'll paste that in and paste that in.
I'm just going to check the database before I do go forward, because I want to make sure that I don't
have any users in my database.
I suspect, though, because of the nature of this request, it's going to have created the Bob user,
but not the admin user.
Let's go take a look.
And if I take a look at the store DB, then we should see all of our additional tables now.
And if I take a look at ASP users or ASP.Net users, then sure, I've got Bob in there, so that makes
it tricky.
Now because of that mistake, then the only way I get down to that line of code to add the user is if
I do not have any users in my database.
So if you do run into this kind of problems, then I won't delete this mistake and edit it out.
I'll demonstrate something that you may well need to use yourself as you build the code.
Very easy to make mistakes and it's not a problem to make mistakes.
It's what we do to correct them.
And in this case, the quickest resolution to this problem is simply to drop the database and then restart
the app.
Because then I won't have a Bob user in my database.
This line of code will execute again.
And now that I've updated this, I shouldn't get the same problem.
So that's the approach I'll take.
I'll stop the application and I'll use dotnet EF database drop to get rid of that instance of that database.
And I'll say yes when I get the confirmation.
And yes, I do.
And that database has gone.
So now if I execute dotnet watch again I should get success this time.
And sure that looks a bit cleaner.
It happened quite quickly, but I can see all of the products are being inserted back into the database.
And yeah, that means everything is fine.
One thing that will not be fine though, and something that I'll need to think about when I get to it,
is the baskets that's now gone from our database.
So when our client browser tries to get it, if I have a basket that's going to fail.
So I would need to manually clear out my cookies before that functionality works again.
But that's fine.
I'll just remember that for a bit later.
But now we've got a database with users in and we've got login and register functionality.
So let's go and take a look at postman and take a look in section nine at some of the requests that
we've got now with this identity endpoint.
It does give us two ways to log in.
The first way is with a JWT.
And if I take a look at the body of the request, then I send this up as an email and password.
That's what our API endpoint is expecting.
And I just want to point out some weirdness here as well.
I did mention that we needed to keep our username and the email the same, and I just want to point
out why that is.
If we take a look at the login endpoint, this tells us that it expects for this endpoint and these
endpoints themselves.
They're not customizable.
I can't swap this for a username.
It has to be email.
If I do want my own login endpoint, then I have to write the code for a login endpoint myself.
So that's what it's expecting.
But the reason there's some weirdness in this and I'll just paste in a URL for the GitHub code because
it's all open source.
We can see the code that we're using for these identity API endpoints.
I just want to point out in this code, if I take a look at the login method and this kind of tricky
to read because it uses the minimal API approach.
So we don't have a program class here, we've got these route group map post and then login.
This is the one that I'm looking for.
This uses the sign in manager to check our username and password.
And this method here the await sign in manager password sign in async takes in the login email login
password.
So far so consistent right?
Well if I look for sign in manager password sign in async and take a look at the documentation for this
particular method in the Microsoft Docs.
And we take a look at what this is looking for this method then this is looking for a username.
It's not looking for an email.
This is specifically using a username and password.
It doesn't take an email the password sign in async.
So their usage of this is kind of unusual because if I was writing this code, I would say, well this
should be username because that's what the sign in manager is expecting.
But they've gone for email and it does make it a little bit weird how we use this.
And the way that I'm approaching it is just to make sure the email and the username are identical.
And then whether or not I use the email or the username because they're both the same, it doesn't matter
as long as I specify the property as email, because that is what the endpoint is expecting, then it
works just fine.
So let's go back to postman.
And they've got email of Bob at test.com and the password.
And if I click send then what we get back here is an access token and the refresh token.
And this is the JWT approach.
Now, with a web application that's browser based, we can use either we could use this access token.
And if we take this access token and let's just go to another site and I'll just use jwt.io as an example.
Then I can paste in this token into this site and it will give me the details about it or not in this
case, because it's not actually a JWT, it's a JWT, a JSON web token wrapped up in something else.
So it's not something that we can directly look at inside here.
Possibly.
Let's change.
I actually did think that this was possible previously, and I've copied everything there.
Sure.
So it's not something that we can just decode and take a look at.
But we could send up this token to authenticate.
That's one way to go about it.
It's not the way that we're going to use.
And if we had a mobile version of our app and mobile apps do not support cookies, then we could use
this approach.
The approach that we're going to use for authentication is to use a cookie.
And the way that we use this version of the endpoint is we add use cookies as a query string onto the
endpoint.
And if I take a look at the body, the same thing.
We're using the same username and password here.
If I click send then we get a 200 okay.
And it doesn't look like anything has happened, but something has happened.
If I take a look at my cookies and once again, postman is a bit weird like this, I need to click cookies
a second time.
And now for some reason that I don't know, I can now see the cookies that are available.
So this is our authentication token inside here that we can see and we can get our cookie effectively
that's going to be sent up with every single request.
And then we'll be using that cookie to authenticate our users.
So once we've logged in the idea is we log into our API That sends back our cookie and our browser stores
that cookie.
It is an HTTP only cookie, and that means we cannot access this cookie from our react application.
So that's something we need to think of and work around as well.
But it is the more secure version of authenticating to our API.
JWT is JSON web tokens the first option?
They're considered less secure because you still need to store that token somewhere if you want to persist
the login.
Because our client app, the react app, doesn't maintain a connection with our API.
Then we need to persist somewhere like local storage, for example.
But then local storage is accessible from JavaScript code, so the cookie is considered more secure
because of this flag that we can put inside a cookie.
Okay, so whilst we do have a register user endpoint, we're not actually going to use it.
And we're going to take a look at a slightly different approach for registering a user.
And we'll take a look at that next.