1
00:00:01,079 --> 00:00:02,532
- [Narrator] Hi and
welcome back to the course.

2
00:00:02,532 --> 00:00:04,359
In this video, we're going to be

3
00:00:04,359 --> 00:00:06,297
doing something really important,

4
00:00:06,297 --> 00:00:08,780
which is authentication.

5
00:00:08,780 --> 00:00:09,799
Now the first thing to do is

6
00:00:09,799 --> 00:00:14,693
to instal a required
library, which is Flask JWT.

7
00:00:14,693 --> 00:00:16,341
So let's go over to the terminal

8
00:00:16,341 --> 00:00:19,174
and just do pip instal Flask JWT.

9
00:00:20,943 --> 00:00:22,134
Make sure that you are

10
00:00:22,134 --> 00:00:24,519
in your virtual environment for this,

11
00:00:24,519 --> 00:00:27,875
so the library gets
installed in the right place.

12
00:00:27,875 --> 00:00:30,584
I've already got it installed,
so nothing really happens.

13
00:00:30,584 --> 00:00:33,097
But for you, it'll instal
the library and get it,

14
00:00:33,097 --> 00:00:35,264
make it available for you.

15
00:00:36,847 --> 00:00:38,597
So what is Flask JWT?

16
00:00:39,583 --> 00:00:41,914
Well really, what is JWT?

17
00:00:41,914 --> 00:00:46,274
JWT stands for JSON Web Token.

18
00:00:46,274 --> 00:00:50,441
And essentially, all that it
is, is an obfuscation of data.

19
00:00:51,431 --> 00:00:54,523
And that is we're going
to be encoding some data

20
00:00:54,523 --> 00:00:56,961
and that's a JSON Web Token.

21
00:00:56,961 --> 00:01:00,878
For example, if I want to
send you a private message

22
00:01:00,878 --> 00:01:02,078
that says, "Hello,"

23
00:01:02,078 --> 00:01:04,954
and I don't want anybody
else to be able to see it,

24
00:01:04,954 --> 00:01:07,834
I can encode that message
so that nobody else

25
00:01:07,834 --> 00:01:09,944
can understand it unless they

26
00:01:09,944 --> 00:01:14,157
have a particular decryption key,

27
00:01:14,157 --> 00:01:16,856
so a way to decrypt it.

28
00:01:16,856 --> 00:01:20,856
We are going to be doing
that but with user IDs.

29
00:01:21,982 --> 00:01:25,506
So a user is going to be an entity

30
00:01:25,506 --> 00:01:28,640
that has a unique identifying number

31
00:01:28,640 --> 00:01:31,271
and a username and a password.

32
00:01:31,271 --> 00:01:34,035
The user is going to send us
a username and a password,

33
00:01:34,035 --> 00:01:37,943
and we're going to send
them, the client really,

34
00:01:37,943 --> 00:01:41,776
a JWT and that JWT is
going to be the user ID.

35
00:01:43,910 --> 00:01:46,416
When the client has the JWT

36
00:01:46,416 --> 00:01:50,556
they can send it to us
with any request they make

37
00:01:50,556 --> 00:01:54,029
and when they do that
it's going to tell us

38
00:01:54,029 --> 00:01:57,410
that they have previously authenticated,

39
00:01:57,410 --> 00:02:00,481
that means they are logged in.

40
00:02:00,481 --> 00:02:01,779
It sounds all a bit abstract,

41
00:02:01,779 --> 00:02:03,755
so let's get right into it.

42
00:02:03,755 --> 00:02:06,155
Just the beginning I
mentioned that in order

43
00:02:06,155 --> 00:02:09,583
to encrypt and be able to then
understand what was encrypted

44
00:02:09,583 --> 00:02:12,059
you need some sort of key,

45
00:02:12,059 --> 00:02:14,112
and we do have that in Flask.

46
00:02:14,112 --> 00:02:15,859
All we have to do is down here,

47
00:02:15,859 --> 00:02:18,231
below app or somewhere around there,

48
00:02:18,231 --> 00:02:19,814
type app.secret_key

49
00:02:21,113 --> 00:02:23,310
and then type in a secret key.

50
00:02:23,310 --> 00:02:25,585
This key should be secret.

51
00:02:25,585 --> 00:02:28,954
So for example, if you were
gonna publish this code,

52
00:02:28,954 --> 00:02:33,037
you would not want the
secret key to be visible.

53
00:02:33,037 --> 00:02:35,050
I'm going to just put Jose in there.

54
00:02:35,050 --> 00:02:36,788
It doesn't matter what it is at this point

55
00:02:36,788 --> 00:02:40,234
but do know that if this
were being used by people

56
00:02:40,234 --> 00:02:41,981
and this was a production API,

57
00:02:41,981 --> 00:02:45,274
this would have to be secret
and it would have to be secure.

58
00:02:45,274 --> 00:02:48,789
So something long and complicated.

59
00:02:48,789 --> 00:02:50,943
Okay, they next thing we're going to do

60
00:02:50,943 --> 00:02:54,261
is we're going to create
a couple of functions.

61
00:02:54,261 --> 00:02:56,105
I'm going to go into
another file for that.

62
00:02:56,105 --> 00:02:58,101
So I'm just going to
create a new file there

63
00:02:58,101 --> 00:03:00,018
and call it security.py

64
00:03:01,838 --> 00:03:04,496
This security.py file is going

65
00:03:04,496 --> 00:03:08,663
to contain a few important functions.

66
00:03:11,678 --> 00:03:13,023
The first thing it's going to have

67
00:03:13,023 --> 00:03:15,549
is it's going to have a in memory table

68
00:03:15,549 --> 00:03:18,206
of our registered users.

69
00:03:18,206 --> 00:03:20,284
So it's going to be something like Users.

70
00:03:20,284 --> 00:03:22,003
There's gonna be a table with,

71
00:03:22,003 --> 00:03:25,420
right now a single user, that has ID '1'.

72
00:03:26,377 --> 00:03:30,972
The user name and 'bob'

73
00:03:30,972 --> 00:03:35,091
and password 'asdf'.

74
00:03:35,091 --> 00:03:37,154
Okay, thus or user's table.

75
00:03:37,154 --> 00:03:40,659
Just pretend this is
some sort of database.

76
00:03:40,659 --> 00:03:44,144
Then we're going to
have user name mapping.

77
00:03:44,144 --> 00:03:47,894
And all this is going
to be is the following.

78
00:03:48,743 --> 00:03:52,076
Bob is going to be this dictionary here.

79
00:03:55,490 --> 00:03:58,076
And then we're going to
have a user ID mapping,

80
00:03:58,076 --> 00:04:00,576
which is going to be that '1',

81
00:04:03,026 --> 00:04:06,026
is going to be this dictionary here.

82
00:04:08,884 --> 00:04:13,377
Okay, so all that we've done
is we created a table of users,

83
00:04:13,377 --> 00:04:14,441
and then we've said,

84
00:04:14,441 --> 00:04:18,274
now I want to be able
to have an index on bob.

85
00:04:19,616 --> 00:04:23,366
So, we've created another
dictionary that has

86
00:04:25,176 --> 00:04:26,886
the following.

87
00:04:26,886 --> 00:04:29,553
A key which is bob, the username

88
00:04:30,389 --> 00:04:33,893
and then the values of
the dictionary in it

89
00:04:33,893 --> 00:04:38,060
and then another instance
which has the ID as a key

90
00:04:40,068 --> 00:04:44,555
and the values there of
the dictionary as the body.

91
00:04:44,555 --> 00:04:48,994
If we had many users, then
this would grow accordingly

92
00:04:48,994 --> 00:04:52,152
and what would happen then
is that we would be able

93
00:04:52,152 --> 00:04:56,319
to say something like
username_mapping('bob')

94
00:04:58,969 --> 00:05:03,118
and that would give us
the bob's user really.

95
00:05:03,118 --> 00:05:07,187
Or using userid_mapping

96
00:05:07,187 --> 00:05:11,126
and that would give us the bob's the user.

97
00:05:11,126 --> 00:05:12,628
So why do we do this?

98
00:05:12,628 --> 00:05:16,426
So we don't have to iterate
over our list every time.

99
00:05:16,426 --> 00:05:18,898
Essentially, we have this mapping here,

100
00:05:18,898 --> 00:05:20,846
which lets us immediately find

101
00:05:20,846 --> 00:05:22,226
the user that we're looking for,

102
00:05:22,226 --> 00:05:23,826
just by knowing its username

103
00:05:23,826 --> 00:05:25,996
or immediately find the
user that we're looking for

104
00:05:25,996 --> 00:05:28,829
just by knowing its user ID, okay.

105
00:05:31,125 --> 00:05:31,958
Perfect.

106
00:05:31,958 --> 00:05:33,196
Now that we've got that,

107
00:05:33,196 --> 00:05:35,586
we're gonna create our tool functions.

108
00:05:35,586 --> 00:05:39,396
One function is going to be
used to authenticate a user.

109
00:05:39,396 --> 00:05:42,859
It's the function that given
a user name and a password,

110
00:05:42,859 --> 00:05:46,606
is going to select the correct
user name from our list.

111
00:05:46,606 --> 00:05:47,717
Right now there's only one,

112
00:05:47,717 --> 00:05:49,717
but there could be many.

113
00:05:50,796 --> 00:05:53,120
This is the authenticate function

114
00:05:53,120 --> 00:05:55,587
and it takes in a user name and a password

115
00:05:55,587 --> 00:05:56,796
and the first thing that it's gonna do

116
00:05:56,796 --> 00:06:00,213
is it's going to find a user by username.

117
00:06:02,513 --> 00:06:06,430
Username_mapping.get(username)

118
00:06:08,992 --> 00:06:12,752
.get is another way of
accessing a dictionary.

119
00:06:12,752 --> 00:06:15,123
So all we do is put the key in there

120
00:06:15,123 --> 00:06:19,365
and the .get method gives
us the value of the key.

121
00:06:19,365 --> 00:06:21,237
The added benefit which you don't get

122
00:06:21,237 --> 00:06:23,804
if you use this square bracket notation

123
00:06:23,804 --> 00:06:26,522
is that you can also set a default value,

124
00:06:26,522 --> 00:06:28,612
which we're going to do just now.

125
00:06:28,612 --> 00:06:30,692
We're going to set the
default value to none.

126
00:06:30,692 --> 00:06:35,499
What that means, is that if
there isn't a username key,

127
00:06:35,499 --> 00:06:36,615
for this username,

128
00:06:36,615 --> 00:06:39,891
if there isn't a user with
this username in the mapping,

129
00:06:39,891 --> 00:06:41,921
we're going to return none.

130
00:06:41,921 --> 00:06:46,381
Okay and then we can
say if user is not none,

131
00:06:46,381 --> 00:06:49,065
but we can delete that
because it's implied

132
00:06:49,065 --> 00:06:53,232
and user.password = password,

133
00:06:54,634 --> 00:06:57,717
we're going to return the user, okay.

134
00:06:59,611 --> 00:07:02,194
And then the identity function,

135
00:07:03,443 --> 00:07:06,641
which is unique to Flask JWT,

136
00:07:06,641 --> 00:07:08,381
the extension that we've installed,

137
00:07:08,381 --> 00:07:10,941
the identity function takes in a payload

138
00:07:10,941 --> 00:07:15,200
and the payload is the
contents of the JWT Token

139
00:07:15,200 --> 00:07:17,712
and then we're going
to extract the user ID

140
00:07:17,712 --> 00:07:19,129
from that payload

141
00:07:21,091 --> 00:07:22,551
and once we have the user ID,

142
00:07:22,551 --> 00:07:26,830
we can retrieve the specific
user that matches this payload

143
00:07:26,830 --> 00:07:30,997
by just doing return
userID_mapping.get(userID)

144
00:07:34,040 --> 00:07:36,509
or none as a default.

145
00:07:36,509 --> 00:07:39,791
See how these mappings now
start to make a bit more sense.

146
00:07:39,791 --> 00:07:42,100
Because we can directly retrieve users

147
00:07:42,100 --> 00:07:46,267
by user ID or username without
having to do any iteration.

148
00:07:50,113 --> 00:07:51,443
Now that this is here,

149
00:07:51,443 --> 00:07:54,945
I would like to extend this
slightly before we move on

150
00:07:54,945 --> 00:07:57,435
and I'm sort of going to do
this as part of this video.

151
00:07:57,435 --> 00:07:58,775
And that's by creating a new file

152
00:07:58,775 --> 00:08:01,108
that is going to be user.py.

153
00:08:02,267 --> 00:08:06,565
In the user.py file, we're
going to create a user object.

154
00:08:06,565 --> 00:08:09,685
So that instead of having
good old dictionaries,

155
00:08:09,685 --> 00:08:11,216
we have proper objects.

156
00:08:11,216 --> 00:08:13,297
So let's go into our user.py file

157
00:08:13,297 --> 00:08:15,464
and create the user in it.

158
00:08:16,625 --> 00:08:20,625
Self,_id, username,password

159
00:08:21,492 --> 00:08:22,325
And all this is going to do

160
00:08:22,325 --> 00:08:25,325
is it's going to be a store of data.

161
00:08:34,128 --> 00:08:36,693
So now when we create a user object,

162
00:08:36,693 --> 00:08:37,678
that's going to be essentially

163
00:08:37,678 --> 00:08:40,345
the same thing as the dictionary

164
00:08:41,681 --> 00:08:46,510
Do notice I'm using _ID
instead the good old id.

165
00:08:46,510 --> 00:08:48,551
Because ID is a Python Keyword

166
00:08:48,551 --> 00:08:50,960
and we don't want to use
that as a variable name

167
00:08:50,960 --> 00:08:52,877
self.id is fine though.

168
00:08:55,634 --> 00:08:58,673
So now we know that
we've got the user here,

169
00:08:58,673 --> 00:09:00,564
we can import it

170
00:09:00,564 --> 00:09:03,182
because the user file
is in the same directory

171
00:09:03,182 --> 00:09:05,791
as the security file in which we are in.

172
00:09:05,791 --> 00:09:08,622
We can just do from user, import user

173
00:09:08,622 --> 00:09:10,251
and that accesses the user file

174
00:09:10,251 --> 00:09:13,221
and imports the user class from it.

175
00:09:13,221 --> 00:09:17,144
And then, our users list,
instead of being dictionaries

176
00:09:17,144 --> 00:09:17,977
can now be

177
00:09:22,020 --> 00:09:24,099
things like that.

178
00:09:24,099 --> 00:09:28,081
And our mappings can be
improve substantially.

179
00:09:28,081 --> 00:09:31,335
Instead of having
essentially a copy, paste

180
00:09:31,335 --> 00:09:33,449
of the same thing over and over again,

181
00:09:33,449 --> 00:09:36,115
we're going to do something like this.

182
00:09:36,115 --> 00:09:40,115
U.username: u for u is users

183
00:09:41,119 --> 00:09:43,608
and this is a set comprehension.

184
00:09:43,608 --> 00:09:48,443
But instead of assigning
values, u for u is users,

185
00:09:48,443 --> 00:09:51,193
we're assigning key value pairs.

186
00:09:51,193 --> 00:09:52,693
So u.username is u

187
00:09:54,154 --> 00:09:55,547
and for the first user,

188
00:09:55,547 --> 00:09:59,214
that's going to be bob is this object.

189
00:09:59,214 --> 00:10:01,024
If there was more users,

190
00:10:01,024 --> 00:10:03,876
then the next user Ralph
would be this other object

191
00:10:03,876 --> 00:10:06,215
and so on and so on.

192
00:10:06,215 --> 00:10:09,124
And the user ID mapping
is going to be the same

193
00:10:09,124 --> 00:10:13,291
but u.id is u for u in users, okay.

194
00:10:18,079 --> 00:10:21,496
That does make things a lot more concise.

195
00:10:23,913 --> 00:10:26,634
Hopefully, that does make a lot of sense

196
00:10:26,634 --> 00:10:28,514
and if it doesn't,
please do ask a question

197
00:10:28,514 --> 00:10:29,657
in the course Q&A.

198
00:10:29,657 --> 00:10:32,824
More than happy to help out with that.

199
00:10:34,103 --> 00:10:38,523
Also, for some people
who are using Python 2.7,

200
00:10:38,523 --> 00:10:42,542
it's usually a good idea to
not compare strings directly

201
00:10:42,542 --> 00:10:43,604
with equal, equal.

202
00:10:43,604 --> 00:10:46,544
Because in different systems
and different Python versions,

203
00:10:46,544 --> 00:10:48,632
things may get a bit more complicated,

204
00:10:48,632 --> 00:10:50,524
especially when you bring in the subject

205
00:10:50,524 --> 00:10:53,567
of string and coding.

206
00:10:53,567 --> 00:10:55,047
I don't know if you've
heard about these things

207
00:10:55,047 --> 00:10:58,047
but asky, unicode, things like that.

208
00:10:59,246 --> 00:11:01,005
But fortunately, Flask comes

209
00:11:01,005 --> 00:11:04,216
with the nice library called werkseug,

210
00:11:04,216 --> 00:11:07,285
at least I think I'm
pronouncing that right,

211
00:11:07,285 --> 00:11:10,535
and that has a very nice, safe_str_cmp,

212
00:11:12,282 --> 00:11:14,310
safe string compare.

213
00:11:14,310 --> 00:11:19,221
So we can import safe string
compare from werkseug.security

214
00:11:19,221 --> 00:11:23,388
and all that really does
is aid comparison strings.

215
00:11:26,414 --> 00:11:28,997
So then we call it in this way,

216
00:11:31,811 --> 00:11:32,811
and properly

217
00:11:34,050 --> 00:11:36,339
and now we've got safe string compare,

218
00:11:36,339 --> 00:11:39,057
which basically returns true
if the strings are the same

219
00:11:39,057 --> 00:11:42,357
but it works on all the Python versions

220
00:11:42,357 --> 00:11:45,428
and all different systems,
servers and things like that.

221
00:11:45,428 --> 00:11:47,858
So it's just a bit safer
way of comparing strings

222
00:11:47,858 --> 00:11:50,779
and all different encodings as well.

223
00:11:50,779 --> 00:11:53,608
Okay, so now that we've got this here,

224
00:11:53,608 --> 00:11:56,388
we are going to be able
to use the authenticate

225
00:11:56,388 --> 00:12:00,555
and the identity functions to
essentially log in the users

226
00:12:01,688 --> 00:12:04,429
and then be able to identify them.

227
00:12:04,429 --> 00:12:06,158
At the end of this video, which is now,

228
00:12:06,158 --> 00:12:07,569
this doesn't make a lot of sense.

229
00:12:07,569 --> 00:12:08,669
I do appreciate that

230
00:12:08,669 --> 00:12:11,062
but please bare with
me until the next video

231
00:12:11,062 --> 00:12:13,309
where we're going to
bring everything together

232
00:12:13,309 --> 00:12:15,309
by finalising the ap.py.

233
00:12:16,299 --> 00:12:17,369
I'll see you there.

