WEBVTT

1
00:00:01.330 --> 00:00:02.910
<v ->Hi guys and welcome back.</v>

2
00:00:02.910 --> 00:00:04.580
In this video, we're going to start learning

3
00:00:04.580 --> 00:00:06.320
about decorators.

4
00:00:06.320 --> 00:00:08.210
Decorators are great in Python

5
00:00:08.210 --> 00:00:12.390
because they allow us to very easily modify functions.

6
00:00:12.390 --> 00:00:13.940
So let's learn more about them.

7
00:00:15.090 --> 00:00:18.490
Here we've got a user dictionary that has a username and

8
00:00:18.490 --> 00:00:20.890
an access level of guest.

9
00:00:20.890 --> 00:00:24.167
Let's say that guests can't access this function here

10
00:00:24.167 --> 00:00:25.350
get_admin_password

11
00:00:25.350 --> 00:00:28.310
which returns the password to your admin panel.

12
00:00:28.310 --> 00:00:29.143
But as you can see,

13
00:00:29.143 --> 00:00:31.230
if we print out get_admin_password

14
00:00:31.230 --> 00:00:32.960
at the moment, even though we're a guest

15
00:00:32.960 --> 00:00:35.210
we're gonna get out 1234.

16
00:00:35.210 --> 00:00:36.310
There's nothing in this function

17
00:00:36.310 --> 00:00:37.933
to prevent us from doing that.

18
00:00:38.910 --> 00:00:42.360
So, the output of this video should be

19
00:00:43.280 --> 00:00:46.430
to get this function secured so that

20
00:00:46.430 --> 00:00:50.093
people that are guests cannot get the value out.

21
00:00:51.270 --> 00:00:54.380
Now of course, the clear thing that you can do

22
00:00:54.380 --> 00:00:56.320
is to put an if statement in here.

23
00:00:56.320 --> 00:01:01.320
If the user's access level is == to admin,

24
00:01:01.460 --> 00:01:03.970
then you can print out this function.

25
00:01:03.970 --> 00:01:05.550
Otherwise, you can't.

26
00:01:05.550 --> 00:01:06.424
So this will work

27
00:01:06.424 --> 00:01:09.140
if you run that, you don't get anything,

28
00:01:09.140 --> 00:01:10.360
but of course as you know,

29
00:01:10.360 --> 00:01:13.810
get_admin_password is still un-secure

30
00:01:13.810 --> 00:01:15.830
so you can still print that out

31
00:01:15.830 --> 00:01:17.650
and it'll still work.

32
00:01:17.650 --> 00:01:18.860
Because what we've done is

33
00:01:18.860 --> 00:01:23.860
we have protected this specific call to get_admin_password,

34
00:01:23.900 --> 00:01:27.290
but we haven't protected this one.

35
00:01:27.290 --> 00:01:30.383
So, this is probably not exactly what we want to do.

36
00:01:31.760 --> 00:01:32.593
The next thing we can do

37
00:01:32.593 --> 00:01:35.610
is we can define a secure function.

38
00:01:35.610 --> 00:01:37.863
For example, secure_get_admin.

39
00:01:38.926 --> 00:01:41.810
And in this one, if the user's access level is admin

40
00:01:44.240 --> 00:01:47.420
then we can return the password 1234.

41
00:01:47.420 --> 00:01:49.040
Now, a couple of things.

42
00:01:49.040 --> 00:01:51.630
Clearly get_admin_password is still defined,

43
00:01:51.630 --> 00:01:53.810
so that is not going to work,

44
00:01:53.810 --> 00:01:58.760
but secure_get_admin does protect the password.

45
00:01:58.760 --> 00:02:01.790
Running that gives you None, first of all

46
00:02:01.790 --> 00:02:03.230
when you run secure_get_admin

47
00:02:03.230 --> 00:02:05.350
because we didn't return 1234.

48
00:02:05.350 --> 00:02:07.600
Instead, we returned None which is a default.

49
00:02:07.600 --> 00:02:09.743
Then you get 1234 the next time around.

50
00:02:10.920 --> 00:02:12.580
So of course, what you may want to do

51
00:02:12.580 --> 00:02:14.719
is delete this one entirely.

52
00:02:14.719 --> 00:02:17.633
But, that poses a small problem.

53
00:02:17.633 --> 00:02:20.960
Which is that all the functions

54
00:02:20.960 --> 00:02:22.560
where you want it to be secure,

55
00:02:22.560 --> 00:02:25.120
you're going to have to add this if statement.

56
00:02:25.120 --> 00:02:27.750
And up 'til now, that is what you would have done

57
00:02:27.750 --> 00:02:29.760
if you didn't know about decorators.

58
00:02:29.760 --> 00:02:33.571
But, a decorator will allow us to modify this function

59
00:02:33.571 --> 00:02:36.620
to secure it without having to replace

60
00:02:36.620 --> 00:02:40.800
all of our functions by its secure counterparts.

61
00:02:40.800 --> 00:02:42.943
So, we don't want to do that either.

62
00:02:44.960 --> 00:02:46.050
Instead what we could do

63
00:02:46.050 --> 00:02:49.880
is define another function, secure_function

64
00:02:49.880 --> 00:02:51.170
that takes in a function.

65
00:02:51.170 --> 00:02:53.990
We've learned about first class functions,

66
00:02:53.990 --> 00:02:56.730
so we can take it in as a function there,

67
00:02:56.730 --> 00:03:01.590
and we'll say if the user's access level is == to admin

68
00:03:03.890 --> 00:03:06.040
then we will return func.

69
00:03:06.040 --> 00:03:07.440
Otherwise we'll return none.

70
00:03:07.440 --> 00:03:09.240
And now what you may be tempted to do

71
00:03:09.240 --> 00:03:10.470
is to do something like

72
00:03:10.470 --> 00:03:13.877
get_admin_password = secure function(get_admin_password).

73
00:03:17.850 --> 00:03:19.363
So, will this work?

74
00:03:20.480 --> 00:03:23.030
Well, let's run through the code.

75
00:03:23.030 --> 00:03:25.040
We've got secure_function being called

76
00:03:25.040 --> 00:03:26.970
which takes in get_admin_password,

77
00:03:26.970 --> 00:03:29.110
and when this line runs,

78
00:03:29.110 --> 00:03:31.680
we're going to check the user's access level

79
00:03:31.680 --> 00:03:32.860
and see if it's admin.

80
00:03:32.860 --> 00:03:35.793
And if it is, we're going to return func.

81
00:03:37.685 --> 00:03:39.035
So, let's see what happens.

82
00:03:41.310 --> 00:03:43.010
Now you get an error.

83
00:03:43.010 --> 00:03:45.560
NoneType object is not callable.

84
00:03:45.560 --> 00:03:48.700
Because of course, when we ran this code

85
00:03:48.700 --> 00:03:50.140
i.e., this line here,

86
00:03:50.140 --> 00:03:52.930
the user's access level was guest not admin.

87
00:03:52.930 --> 00:03:54.520
So we didn't return func,

88
00:03:54.520 --> 00:03:56.450
we returned none which is the default.

89
00:03:56.450 --> 00:03:59.270
So get_admin_password = none.

90
00:03:59.270 --> 00:04:02.320
Then we're trying to run none as if it were a function,

91
00:04:02.320 --> 00:04:04.520
but you can't do that so you get an error.

92
00:04:04.520 --> 00:04:05.580
What you would have to do is

93
00:04:05.580 --> 00:04:07.620
make sure that your user is an admin

94
00:04:07.620 --> 00:04:09.780
before you run any of your code.

95
00:04:09.780 --> 00:04:12.800
And then it will work and you will get 1234.

96
00:04:12.800 --> 00:04:16.653
So this is a step closer to what we want,

97
00:04:17.540 --> 00:04:21.100
but alas it requires that our user be an admin

98
00:04:21.100 --> 00:04:24.080
before we secure our functions.

99
00:04:24.080 --> 00:04:26.440
Ideally we would like to do something that checks

100
00:04:26.440 --> 00:04:29.480
the user's access level when you call the function,

101
00:04:29.480 --> 00:04:31.033
not when you define it.

102
00:04:32.900 --> 00:04:34.740
So, here's what we're gonna do.

103
00:04:34.740 --> 00:04:36.790
We're still going to take in a function

104
00:04:36.790 --> 00:04:40.360
but now we're going to define another function,

105
00:04:40.360 --> 00:04:42.270
which I'm going to call secure_function.

106
00:04:42.270 --> 00:04:44.603
This one I'm gonna call make_secure.

107
00:04:45.710 --> 00:04:48.820
This one doesn't take any parameters,

108
00:04:48.820 --> 00:04:50.906
and it is the one that checks.

109
00:04:50.906 --> 00:04:55.700
And, it returns calling the original function.

110
00:04:55.700 --> 00:04:59.310
Then, here we return secure_function.

111
00:04:59.310 --> 00:05:01.360
So this is a decorator.

112
00:05:01.360 --> 00:05:02.550
What happens now, and by the way

113
00:05:02.550 --> 00:05:04.450
this should be make_secure.

114
00:05:04.450 --> 00:05:06.760
What happens now is that get_admin_password,

115
00:05:06.760 --> 00:05:08.933
this function that we want to secure,

116
00:05:10.120 --> 00:05:12.810
is passed to the make_secure function.

117
00:05:12.810 --> 00:05:14.220
This one defines another function,

118
00:05:14.220 --> 00:05:16.070
and by the way, in Python you can define functions

119
00:05:16.070 --> 00:05:18.820
inside a function, so that's totally fine.

120
00:05:18.820 --> 00:05:22.050
And this function here, when called,

121
00:05:22.050 --> 00:05:23.940
will check the user's access level

122
00:05:23.940 --> 00:05:26.350
and return calling the original function

123
00:05:26.350 --> 00:05:27.620
which is get_admin_password.

124
00:05:27.620 --> 00:05:32.340
So it will return 1234 if the user's access level is admin.

125
00:05:32.340 --> 00:05:33.760
So that's this function here,

126
00:05:33.760 --> 00:05:35.680
and then we return the function itself.

127
00:05:35.680 --> 00:05:39.080
Not the function call, but the function itself.

128
00:05:39.080 --> 00:05:43.910
get_admin_password will be equal to this function.

129
00:05:43.910 --> 00:05:47.210
Which calls seemingly itself, but this is okay.

130
00:05:47.210 --> 00:05:49.423
It calls get_admin_password from up here.

131
00:05:50.556 --> 00:05:53.350
So when you call get_admin_password what you're gonna do

132
00:05:53.350 --> 00:05:55.670
is you're going to check the user's access level,

133
00:05:55.670 --> 00:05:58.120
and then you're going to return the result

134
00:05:58.120 --> 00:06:00.250
of calling the function originally,

135
00:06:00.250 --> 00:06:01.863
which will give you 1234.

136
00:06:05.709 --> 00:06:10.080
At the moment you get none, but of course if you

137
00:06:10.080 --> 00:06:13.290
set the user's access level to admin down here

138
00:06:13.290 --> 00:06:14.343
and you run it again,

139
00:06:15.250 --> 00:06:16.510
then you get 1234.

140
00:06:16.510 --> 00:06:17.860
Which is exactly what we wanted.

141
00:06:17.860 --> 00:06:20.800
So this is a simple decorator.

142
00:06:20.800 --> 00:06:23.820
This simple decorator will create a function

143
00:06:23.820 --> 00:06:27.730
and replace the original function with this secure one.

144
00:06:27.730 --> 00:06:31.870
So that you can no longer call get_admin_password

145
00:06:31.870 --> 00:06:34.963
without having the admin access level.

146
00:06:35.910 --> 00:06:38.240
Now if you wanted to add a little bit of error handling

147
00:06:38.240 --> 00:06:39.640
you can do an else here

148
00:06:39.640 --> 00:06:41.197
and you can return something like

149
00:06:41.197 --> 00:06:45.880
"No admin permissions for {user['username']}."

150
00:06:47.600 --> 00:06:50.490
and that'll give you a nicer idea of what's going on

151
00:06:50.490 --> 00:06:52.290
if you don't have admin permissions.

152
00:06:54.330 --> 00:06:55.500
That's everything for this video.

153
00:06:55.500 --> 00:06:57.770
This is a simple decorator,

154
00:06:57.770 --> 00:06:59.910
and now in the next one we're going to learn more

155
00:06:59.910 --> 00:07:02.700
about using the @ syntax for decorators

156
00:07:02.700 --> 00:07:05.520
that makes this much simpler, and much easier

157
00:07:05.520 --> 00:07:07.740
to re-use and secure multiple functions

158
00:07:07.740 --> 00:07:09.500
if that's what you want to do.

159
00:07:09.500 --> 00:07:10.390
Thanks for joining me,

160
00:07:10.390 --> 00:07:12.140
and I'll see you in the next video.

