WEBVTT

00:00.000 --> 00:00.330
Okay.

00:00.330 --> 00:03.240
What we're going to take a look is creating our own register endpoint.

00:03.240 --> 00:05.370
And why do we have to do this?

00:05.370 --> 00:14.400
Well, because I want to send up the username, which actually in this case I would need to change to

00:14.430 --> 00:24.780
at Test.com for this particular user because of the way that the login endpoint works where we send

00:24.780 --> 00:30.270
up an email, but really that gets compared against the username property in our database.

00:30.270 --> 00:39.330
So if we take a look at the documentation for the register endpoint, which is the one above here,

00:39.330 --> 00:49.050
then this only takes an email and a password and it doesn't set the username for the registered user.

00:49.050 --> 00:56.190
So because of the way that the weirdness, in my opinion, the way that this has been set up where we

00:56.190 --> 01:03.170
use the email to Register a user, but then this email address isn't going to work with the login endpoint.

01:03.170 --> 01:04.700
It has to be a username.

01:04.700 --> 01:08.360
Then we're just going to create our own register endpoint.

01:08.360 --> 01:12.320
In this case anyway, the register endpoint doesn't log in a user.

01:12.380 --> 01:13.880
It doesn't send back a cookie.

01:13.910 --> 01:15.290
It doesn't send back anything else.

01:15.290 --> 01:17.180
It simply creates a user in a database.

01:17.180 --> 01:19.670
And we can just go ahead and create that ourselves.

01:19.670 --> 01:27.500
And we do need to generate a few other endpoints of our own to make our login and authentication system

01:27.500 --> 01:31.820
work how we want it in our application.

01:31.820 --> 01:38.300
So let's head back to VS code and we will create a new controller in our application.

01:38.300 --> 01:41.240
And I'll go to the controllers folder I'll say new file.

01:41.240 --> 01:43.130
And this is going to be a class.

01:43.130 --> 01:47.090
And I'm going to call it account controller and press return.

01:47.090 --> 01:53.180
And this is going to derive from our base API controller.

01:54.200 --> 01:59.800
And we're going to create an endpoint in here that's going to be an HTTP post and we're going to call

01:59.800 --> 02:04.540
it Register and we'll say public async task.

02:04.780 --> 02:11.200
And we're just going to return an action result from this without a type, as we're not going to return

02:11.200 --> 02:15.100
anything from this and we'll call it Register user.

02:15.280 --> 02:17.320
Well I say we're not going to return anything from this.

02:17.320 --> 02:24.280
Every HTTP request demands that we send back an HTTP response, but we're not going to return any user

02:24.280 --> 02:25.210
data with this.

02:25.210 --> 02:28.330
So we don't need to specify a type here.

02:28.330 --> 02:35.500
And what are we going to send up as the arguments though for the register user we need to know the username,

02:35.500 --> 02:38.260
the email and the password.

02:38.920 --> 02:44.470
And in fact we don't need the username if we're going to ask them to, or if we're only going to store

02:44.470 --> 02:49.390
the email as the username, we don't even need the username to be sent up.

02:49.390 --> 02:51.160
So I'll adjust that in postman soon.

02:51.160 --> 02:58.480
But for the register, let's go to our Dtos CTOs folder and we'll create a class and I'm just going

02:58.510 --> 03:06.070
to call it Register DTO, which is going to allow us to receive the properties in the body of the request.

03:06.070 --> 03:09.940
So I'm going to have a property of string that's going to be an email.

03:09.940 --> 03:17.650
And I'm also going to have a prop that's a string that's going to be for the password.

03:17.680 --> 03:23.380
Now with this one I would like validation to take place.

03:23.410 --> 03:30.310
I would like the passwords to be validated by identity because it's going to be a complex password.

03:31.090 --> 03:33.940
I would also like the email to be required.

03:34.780 --> 03:42.040
But if I use required here and well let's just do both and we'll just do a quick example of what's going

03:42.040 --> 03:46.810
to happen using this approach to saying that we want these to be required.

03:46.930 --> 03:51.670
It's not going to have quite the effect that I want in this case, but we'll do this temporarily.

03:51.670 --> 03:54.460
Then we'll come back and take a look at a different approach.

03:54.460 --> 03:58.480
So inside the account controller now we've got our registered DTO.

03:58.510 --> 04:01.300
We can use this for our argument.

04:01.300 --> 04:05.050
So I'll say register DTO and I'll call it Register DTO.

04:05.080 --> 04:10.420
And inside this method we'll create the code to create a new user.

04:10.420 --> 04:17.140
So I'll say var user equals and new user which we get from API entities.

04:17.140 --> 04:26.440
And we'll have our username which is going to equal the register DTO dot email and the email which equals

04:26.440 --> 04:30.100
register dto dot email.

04:30.520 --> 04:34.570
Okay, I can say still a bit weird, but that's what we're going to go with.

04:34.570 --> 04:38.620
And then we need to create our new user in the database.

04:38.620 --> 04:41.650
And this time we'll inject something in here.

04:41.650 --> 04:46.660
But we won't inject the user manager in this time we'll actually inject the sign in manager for something

04:46.660 --> 04:48.250
we're going to do a bit later.

04:48.250 --> 04:52.990
But the sign in manager also gives us access to the user manager as well.

04:53.020 --> 04:57.010
Now the sign in manager does what you think it's going to do.

04:57.010 --> 05:02.320
It's going to take in a username password and then compare that password or the hashed version of that

05:02.320 --> 05:04.180
password in our database.

05:04.180 --> 05:08.440
But for a short term we're just going to use this as a user manager.

05:08.440 --> 05:10.210
And I'll show you what I mean very soon.

05:10.210 --> 05:13.060
So I'm going to give this the user as its type.

05:13.060 --> 05:15.370
And I'll call it sign in manager.

05:15.430 --> 05:22.450
And we're going to create a user just like we did on our seed data using the user manager.

05:22.450 --> 05:26.290
So I'm going to specify var results equals await.

05:26.290 --> 05:28.780
And we need the sign in manager.

05:28.780 --> 05:32.170
And from the sign in manager we can get access to our user manager.

05:32.170 --> 05:34.840
And then we can use the create async method.

05:34.840 --> 05:39.460
And we can pass in the user and the register DTO dot password.

05:40.390 --> 05:48.070
And we can check to see if the results and one of the properties we get back from the results we get

05:48.070 --> 05:54.150
back from our user manager is whether or not it succeeded, and we want to check to see it's not succeeded

05:54.150 --> 05:54.780
in this case.

05:54.780 --> 05:56.640
So I'll add the Not operator.

05:56.790 --> 06:06.390
And we want to effectively return the validation errors from this because our result objects will also

06:06.390 --> 06:09.630
contain an errors object with each of the different problems.

06:09.630 --> 06:14.820
So I'm going to loop over that object and see for each error.

06:14.850 --> 06:19.920
VAR error in results dot errors.

06:21.030 --> 06:26.010
Then we're going to use the model state, which we took a look at a bit earlier when we were taking

06:26.010 --> 06:27.390
a look at error handling.

06:27.390 --> 06:34.200
And I'm going to add the model error and say error code and error dot description.

06:35.130 --> 06:40.020
And from here I'm going to return a validation problem.

06:40.020 --> 06:46.980
Now in theory that should give us the email is required passwords not complex enough.

06:46.980 --> 06:49.830
And the different password validation errors we get from this.

06:49.830 --> 06:51.090
I don't think we're going to get that.

06:51.120 --> 06:55.170
I'm doing this just as a quick test really.

06:55.200 --> 06:58.770
Following this, I'm going to use the await sign in manager.

06:58.800 --> 07:03.210
Again use the user manager and we'll use the add to role async.

07:03.210 --> 07:09.360
And we'll put our user in the member role when they do sign up and we will return.

07:09.390 --> 07:10.260
Okay.

07:10.620 --> 07:12.750
So that's our account controller.

07:12.750 --> 07:17.100
And let's see we'll restart our API server.

07:17.100 --> 07:22.350
So I'm just going to use control C and dotnet watch to restart the API server.

07:22.350 --> 07:28.140
And then we'll go back to postman and take a look at a quick test to see how we're doing.

07:28.320 --> 07:32.220
So inside here we don't need the username I'm going to remove that from this request.

07:32.220 --> 07:34.650
So you should not see that on your one.

07:34.680 --> 07:39.840
Going to create a user called Tom at Test.com with the standard password that I have been using.

07:39.840 --> 07:45.790
And just as a quick test, I'm just going to take out the email and I'm going to take out the password

07:45.790 --> 07:49.870
from this request and send this just as it is.

07:49.870 --> 07:51.670
I want to see what we get back.

07:51.970 --> 07:55.030
And okay, so the password is fine.

07:55.030 --> 07:57.130
We've got the errors in there for the password.

07:57.130 --> 07:58.930
We don't see the email one though.

07:59.050 --> 08:02.350
And actually this is not as bad as I thought it would be.

08:02.350 --> 08:04.450
I thought this would be a bit worse.

08:04.450 --> 08:06.460
So we got our password validators.

08:06.820 --> 08:07.810
That's fine.

08:07.810 --> 08:14.050
If I do put in a password that's too weak and click send, what I should see is less validation problems,

08:14.050 --> 08:17.350
but still validation problems, so that's fine as well.

08:17.350 --> 08:22.120
But I'm not seeing the detail about the email is empty.

08:22.510 --> 08:26.290
And what if I did have a complex password but an empty email?

08:26.290 --> 08:29.500
Let's just check this one and click send.

08:29.560 --> 08:30.160
Okay.

08:30.160 --> 08:32.350
So we do get some detail here.

08:32.350 --> 08:36.190
So possibly that's an improvement in dotnet nine.

08:36.190 --> 08:39.490
Do I like this invalid email and invalid username.

08:40.180 --> 08:40.720
Mm.

08:41.410 --> 08:46.170
Let me just demonstrate the way that I was planning to demonstrate this in the first place when it comes

08:46.170 --> 08:48.810
to validating things.

08:48.840 --> 08:55.080
My original plan, and this might well be the plan that I continue with, is to use a data annotation

08:55.650 --> 09:02.700
inside here and specify required for email, with the required coming from data annotations.

09:02.700 --> 09:10.110
Not use the required modifier, but give this an initial value of String.empty and leave data annotation

09:10.110 --> 09:17.010
validation to actually validate the email has been provided, so I'll just restart the API if needed

09:17.010 --> 09:19.230
and doesn't look like it does need to be restarted.

09:19.230 --> 09:21.060
So let's give that a go again.

09:21.480 --> 09:26.970
And yeah, I'll just restart the API because I was expecting a different result than that.

09:29.070 --> 09:32.490
And okay, let's give that another go and click send.

09:32.490 --> 09:35.490
And this is probably my preference.

09:35.490 --> 09:39.600
So where we get an error for the email we just get the email field is required.

09:39.600 --> 09:45.740
And we don't see the stuff about the username for something that I'm sending up just as an email address

09:45.740 --> 09:46.370
here.

09:46.370 --> 09:49.580
So I think that's the approach I'm going to stick with.

09:49.610 --> 09:52.070
But let's make sure that we can register a new user.

09:52.070 --> 09:59.960
So I'm going to put Tom at Test.com back in and I'll click send and we get the 200 okay.

09:59.990 --> 10:02.660
Which means Tom has been created in our database.

10:02.660 --> 10:10.040
And if we go back and try and log in again as this time Tom instead of Bob, then we should get success

10:10.040 --> 10:11.090
and we get the 200.

10:11.120 --> 10:11.870
Okay.

10:11.870 --> 10:16.490
And that cookie will be for the Tom user rather than the Bob user.

10:16.520 --> 10:20.390
Now there are a couple of other endpoints that we need to create.

10:20.930 --> 10:27.020
We surprisingly don't get one to log out, which is designed to remove the cookie from the user's browser.

10:27.020 --> 10:31.760
And we also need one, because we're not going to be able to return a user using this approach.

10:31.760 --> 10:37.160
Using the cookies, we'll need an endpoint so that we can get some user info about the user that has

10:37.160 --> 10:40.220
logged in, and we'll take a look at those next.
