WEBVTT

00:00.020 --> 00:03.710
Okay, now that we've got our configuration in place, we're going to see a couple of users.

00:03.740 --> 00:05.090
We're setting up roles.

00:05.090 --> 00:07.400
We're going to be creating new tables in our database.

00:07.400 --> 00:12.320
First of all, let's create the migration that we need to enable us to do that.

00:12.320 --> 00:14.090
And we'll go back to our API.

00:14.090 --> 00:18.650
And we'll definitely need to stop our API for what we're about to do here.

00:18.650 --> 00:22.190
I don't think anything that I see inside here is genuinely a problem.

00:22.190 --> 00:25.010
It's just hot reloads trying to do its thing.

00:25.010 --> 00:28.820
But please do stop your API and we will.

00:28.850 --> 00:31.340
After we've stopped that, we'll add a new migration.

00:31.340 --> 00:35.120
So we need dotnet EF migrations add.

00:35.120 --> 00:40.070
And I'm just going to say identity added as the migration name and press return.

00:40.070 --> 00:43.490
And this should go ahead and create the migration for us.

00:43.490 --> 00:45.770
That includes the identity tables.

00:45.770 --> 00:49.490
So let's go and take a look at what this has given us.

00:49.520 --> 00:57.770
And if I open up the data folder inside our migrations, we've now got our identity migration.

00:57.920 --> 01:01.380
And inside here we're going to create a bunch of tables.

01:01.380 --> 01:03.600
So we're going to create a table for our roles.

01:03.600 --> 01:08.010
And we have a couple of roles that are going to be added as part of this.

01:08.010 --> 01:14.310
So we can see the name and normalized name that we added in our configuration for seeding those roles

01:14.310 --> 01:14.820
in.

01:14.850 --> 01:21.630
We're also going to have a users table with user related columns, things like username, email, email

01:21.630 --> 01:25.830
confirmed, etc. we're also going to have some ASP.Net role claims.

01:25.830 --> 01:29.580
We're going to get some tables in here that we do not need nor will we touch.

01:29.610 --> 01:30.870
They're not going to do any harm.

01:30.870 --> 01:32.580
They're just going to sit in our database.

01:32.580 --> 01:37.080
This would be one of those examples we're not actually going to use or need.

01:37.080 --> 01:40.920
And then we've got our ASP.Net user claims again same thing.

01:40.920 --> 01:46.890
We won't look at that table ASP.Net users logins another table that will neither need nor look at.

01:46.890 --> 01:52.680
And then we've got our user roles, which of course we will do because each user is going to be placed

01:52.680 --> 01:54.780
in one or more roles.

01:54.780 --> 02:03.370
And then we've got things like user tokens and Evelyn that this is the data that we're creating when

02:03.370 --> 02:05.470
we apply this migration.

02:05.470 --> 02:08.410
It's going to create these two roles inside here.

02:08.410 --> 02:11.020
And could we have used this same technique?

02:11.050 --> 02:13.360
You might be thinking for our users.

02:13.360 --> 02:19.690
Well no not really because we need to use the user manager functionality so that our password that we

02:19.690 --> 02:23.410
provide gets hashed effectively.

02:23.410 --> 02:26.080
So it's not stored in our database in clear text.

02:26.080 --> 02:31.990
If we were to attempt to create a user in this way, we'd definitely have problems with a password.

02:31.990 --> 02:36.490
So it's best to use the user manager to add those users in that way.

02:36.490 --> 02:42.730
So that's our migration, and what we should be able to do now is go back to our terminal, and we will

02:42.730 --> 02:50.350
just use dotnet watch to apply that migration and see the additional data into our database.

02:50.350 --> 02:53.980
So I'll use dotnet watch and see what happens.

02:53.980 --> 02:56.320
And it looks like I've got an error here actually.

02:56.320 --> 02:58.940
So let's see what this is about.

02:58.970 --> 03:07.760
And quite a nasty looking error here and is telling us unique constraint failed for normalized username.

03:08.690 --> 03:14.540
I've got this horrible feeling that copying and pasting continues to be a very bad idea, because if

03:14.540 --> 03:22.340
I've got a duplicate username, then my suspicion is that in my DB initializer class, did I forget

03:22.340 --> 03:24.110
to update the username?

03:24.710 --> 03:33.290
Inside here I did something I forgot to update user and swap that for admin.

03:33.290 --> 03:35.960
So that's the reason for the error I'm getting here.

03:35.960 --> 03:38.930
And I'll paste that in and paste that in.

03:38.930 --> 03:45.500
I'm just going to check the database before I do go forward, because I want to make sure that I don't

03:45.500 --> 03:47.510
have any users in my database.

03:47.510 --> 03:54.320
I suspect, though, because of the nature of this request, it's going to have created the Bob user,

03:54.320 --> 03:56.120
but not the admin user.

03:56.150 --> 03:57.610
Let's go take a look.

03:57.640 --> 04:03.970
And if I take a look at the store DB, then we should see all of our additional tables now.

04:03.970 --> 04:09.820
And if I take a look at ASP users or ASP.Net users, then sure, I've got Bob in there, so that makes

04:09.820 --> 04:10.240
it tricky.

04:10.240 --> 04:16.630
Now because of that mistake, then the only way I get down to that line of code to add the user is if

04:16.630 --> 04:19.270
I do not have any users in my database.

04:19.270 --> 04:27.070
So if you do run into this kind of problems, then I won't delete this mistake and edit it out.

04:27.100 --> 04:31.750
I'll demonstrate something that you may well need to use yourself as you build the code.

04:31.750 --> 04:36.010
Very easy to make mistakes and it's not a problem to make mistakes.

04:36.010 --> 04:37.630
It's what we do to correct them.

04:37.630 --> 04:43.570
And in this case, the quickest resolution to this problem is simply to drop the database and then restart

04:43.570 --> 04:43.960
the app.

04:43.960 --> 04:46.690
Because then I won't have a Bob user in my database.

04:46.720 --> 04:48.880
This line of code will execute again.

04:48.880 --> 04:52.480
And now that I've updated this, I shouldn't get the same problem.

04:52.480 --> 04:54.160
So that's the approach I'll take.

04:54.160 --> 05:03.910
I'll stop the application and I'll use dotnet EF database drop to get rid of that instance of that database.

05:05.200 --> 05:08.980
And I'll say yes when I get the confirmation.

05:09.010 --> 05:11.140
And yes, I do.

05:11.950 --> 05:13.510
And that database has gone.

05:13.510 --> 05:19.510
So now if I execute dotnet watch again I should get success this time.

05:19.510 --> 05:21.520
And sure that looks a bit cleaner.

05:21.670 --> 05:26.500
It happened quite quickly, but I can see all of the products are being inserted back into the database.

05:26.500 --> 05:29.470
And yeah, that means everything is fine.

05:29.470 --> 05:35.080
One thing that will not be fine though, and something that I'll need to think about when I get to it,

05:35.080 --> 05:39.310
is the baskets that's now gone from our database.

05:39.310 --> 05:44.410
So when our client browser tries to get it, if I have a basket that's going to fail.

05:44.410 --> 05:49.420
So I would need to manually clear out my cookies before that functionality works again.

05:49.420 --> 05:50.230
But that's fine.

05:50.230 --> 05:51.790
I'll just remember that for a bit later.

05:51.790 --> 05:58.320
But now we've got a database with users in and we've got login and register functionality.

05:58.350 --> 06:03.960
So let's go and take a look at postman and take a look in section nine at some of the requests that

06:03.960 --> 06:06.450
we've got now with this identity endpoint.

06:06.450 --> 06:08.520
It does give us two ways to log in.

06:08.550 --> 06:12.060
The first way is with a JWT.

06:12.180 --> 06:17.700
And if I take a look at the body of the request, then I send this up as an email and password.

06:17.700 --> 06:20.670
That's what our API endpoint is expecting.

06:20.790 --> 06:23.430
And I just want to point out some weirdness here as well.

06:23.430 --> 06:28.890
I did mention that we needed to keep our username and the email the same, and I just want to point

06:28.890 --> 06:29.820
out why that is.

06:29.820 --> 06:36.060
If we take a look at the login endpoint, this tells us that it expects for this endpoint and these

06:36.060 --> 06:37.260
endpoints themselves.

06:37.260 --> 06:38.700
They're not customizable.

06:38.700 --> 06:40.350
I can't swap this for a username.

06:40.350 --> 06:41.820
It has to be email.

06:42.180 --> 06:48.300
If I do want my own login endpoint, then I have to write the code for a login endpoint myself.

06:48.300 --> 06:49.950
So that's what it's expecting.

06:49.950 --> 06:58.030
But the reason there's some weirdness in this and I'll just paste in a URL for the GitHub code because

06:58.030 --> 06:58.870
it's all open source.

06:58.870 --> 07:03.220
We can see the code that we're using for these identity API endpoints.

07:03.220 --> 07:10.630
I just want to point out in this code, if I take a look at the login method and this kind of tricky

07:10.630 --> 07:13.270
to read because it uses the minimal API approach.

07:13.270 --> 07:18.610
So we don't have a program class here, we've got these route group map post and then login.

07:18.610 --> 07:20.290
This is the one that I'm looking for.

07:20.590 --> 07:25.630
This uses the sign in manager to check our username and password.

07:25.630 --> 07:34.330
And this method here the await sign in manager password sign in async takes in the login email login

07:34.330 --> 07:35.080
password.

07:35.080 --> 07:38.050
So far so consistent right?

07:38.290 --> 07:46.840
Well if I look for sign in manager password sign in async and take a look at the documentation for this

07:46.840 --> 07:50.290
particular method in the Microsoft Docs.

07:50.290 --> 07:56.960
And we take a look at what this is looking for this method then this is looking for a username.

07:57.470 --> 07:58.700
It's not looking for an email.

07:58.700 --> 08:02.150
This is specifically using a username and password.

08:02.150 --> 08:05.060
It doesn't take an email the password sign in async.

08:05.060 --> 08:12.680
So their usage of this is kind of unusual because if I was writing this code, I would say, well this

08:12.680 --> 08:16.310
should be username because that's what the sign in manager is expecting.

08:16.310 --> 08:21.860
But they've gone for email and it does make it a little bit weird how we use this.

08:22.340 --> 08:28.100
And the way that I'm approaching it is just to make sure the email and the username are identical.

08:28.100 --> 08:33.230
And then whether or not I use the email or the username because they're both the same, it doesn't matter

08:33.230 --> 08:38.570
as long as I specify the property as email, because that is what the endpoint is expecting, then it

08:38.570 --> 08:39.410
works just fine.

08:39.410 --> 08:41.120
So let's go back to postman.

08:41.150 --> 08:45.950
And they've got email of Bob at test.com and the password.

08:45.950 --> 08:52.670
And if I click send then what we get back here is an access token and the refresh token.

08:53.430 --> 08:56.160
And this is the JWT approach.

08:56.160 --> 09:02.700
Now, with a web application that's browser based, we can use either we could use this access token.

09:02.700 --> 09:12.570
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.

09:12.660 --> 09:23.340
Then I can paste in this token into this site and it will give me the details about it or not in this

09:23.340 --> 09:31.320
case, because it's not actually a JWT, it's a JWT, a JSON web token wrapped up in something else.

09:31.320 --> 09:34.620
So it's not something that we can directly look at inside here.

09:34.650 --> 09:35.070
Possibly.

09:35.100 --> 09:35.640
Let's change.

09:35.670 --> 09:41.190
I actually did think that this was possible previously, and I've copied everything there.

09:41.220 --> 09:41.820
Sure.

09:41.850 --> 09:45.210
So it's not something that we can just decode and take a look at.

09:45.210 --> 09:48.960
But we could send up this token to authenticate.

09:49.080 --> 09:50.670
That's one way to go about it.

09:50.700 --> 09:52.240
It's not the way that we're going to use.

09:52.240 --> 09:58.060
And if we had a mobile version of our app and mobile apps do not support cookies, then we could use

09:58.060 --> 09:58.780
this approach.

09:58.780 --> 10:02.860
The approach that we're going to use for authentication is to use a cookie.

10:02.860 --> 10:08.320
And the way that we use this version of the endpoint is we add use cookies as a query string onto the

10:08.320 --> 10:08.800
endpoint.

10:08.800 --> 10:10.990
And if I take a look at the body, the same thing.

10:10.990 --> 10:13.000
We're using the same username and password here.

10:13.000 --> 10:15.820
If I click send then we get a 200 okay.

10:15.820 --> 10:19.360
And it doesn't look like anything has happened, but something has happened.

10:19.540 --> 10:26.110
If I take a look at my cookies and once again, postman is a bit weird like this, I need to click cookies

10:26.140 --> 10:27.010
a second time.

10:27.010 --> 10:31.960
And now for some reason that I don't know, I can now see the cookies that are available.

10:31.960 --> 10:39.460
So this is our authentication token inside here that we can see and we can get our cookie effectively

10:39.460 --> 10:42.820
that's going to be sent up with every single request.

10:43.150 --> 10:46.840
And then we'll be using that cookie to authenticate our users.

10:46.840 --> 10:54.170
So once we've logged in the idea is we log into our API That sends back our cookie and our browser stores

10:54.200 --> 10:55.100
that cookie.

10:55.130 --> 11:03.080
It is an HTTP only cookie, and that means we cannot access this cookie from our react application.

11:03.080 --> 11:06.230
So that's something we need to think of and work around as well.

11:06.230 --> 11:11.090
But it is the more secure version of authenticating to our API.

11:11.150 --> 11:14.840
JWT is JSON web tokens the first option?

11:14.840 --> 11:19.970
They're considered less secure because you still need to store that token somewhere if you want to persist

11:19.970 --> 11:20.540
the login.

11:20.540 --> 11:25.340
Because our client app, the react app, doesn't maintain a connection with our API.

11:25.370 --> 11:28.700
Then we need to persist somewhere like local storage, for example.

11:28.730 --> 11:35.450
But then local storage is accessible from JavaScript code, so the cookie is considered more secure

11:35.480 --> 11:38.450
because of this flag that we can put inside a cookie.

11:38.480 --> 11:44.270
Okay, so whilst we do have a register user endpoint, we're not actually going to use it.

11:44.270 --> 11:48.170
And we're going to take a look at a slightly different approach for registering a user.

11:48.170 --> 11:50.660
And we'll take a look at that next.
