@@ -917,7 +917,7 @@ So we can insert the token into our email like this:
917
917
918
918
919
919
[role="sourcecode"]
920
- .src/accounts/views.py (ch17l023 )
920
+ .src/accounts/views.py (ch19l023 )
921
921
====
922
922
[source,python]
923
923
----
@@ -947,43 +947,45 @@ def send_login_email(request):
947
947
framework, and that gets overcomplicated pretty quickly. You can find
948
948
lots more discussion on this if you're curious by doing a bit of googling.
949
949
950
- Two more pieces in the puzzle. We need an authentication backend, whose
951
- job it will be to examine tokens for validity and then return the corresponding
952
- users; then we need to get our login view to actually log users in,
953
- if they can authenticate.((("", startref="Mpythong19")))((("", startref="Pmock19")))
950
+ Two more pieces in the puzzle.
951
+ We need an authentication backend,
952
+ whose job it will be to examine tokens for validity
953
+ and then return the corresponding users;
954
+ then we need to get our login view to actually log users in,
955
+ if they can authenticate.
956
+ ((("", startref="Mpythong19")))((("", startref="Pmock19")))
954
957
955
958
956
959
957
960
958
- De-spiking Our Custom Authentication Backend
959
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
961
+ === De-spiking Our Custom Authentication Backend
960
962
961
- ((("mocks", "de-spiking custom authentication", id="Mdespike19")))((("spiking and de-spiking", "de-spiking", id="SDdesp19")))Our
962
- custom authentication backend is next. Here's how it looked in the spike:
963
+ ((("mocks", "de-spiking custom authentication", id="Mdespike19")))
964
+ ((("spiking and de-spiking", "de-spiking", id="SDdesp19")))
965
+ Our custom authentication backend is next.
966
+ Here's how it looked in the spike:
963
967
964
968
965
969
[[spike-reminder]]
966
970
[role="skipme small-code"]
967
971
[source,python]
968
972
----
969
- class PasswordlessAuthenticationBackend(object):
970
-
971
- def authenticate(self, uid):
972
- print('uid', uid, file=sys.stderr)
973
+ class PasswordlessAuthenticationBackend(BaseBackend):
974
+ def authenticate(self, request, uid):
975
+ print("uid", uid, file=sys.stderr)
973
976
if not Token.objects.filter(uid=uid).exists():
974
- print(' no token found' , file=sys.stderr)
977
+ print(" no token found" , file=sys.stderr)
975
978
return None
976
979
token = Token.objects.get(uid=uid)
977
- print(' got token' , file=sys.stderr)
980
+ print(" got token" , file=sys.stderr)
978
981
try:
979
982
user = ListUser.objects.get(email=token.email)
980
- print(' got user' , file=sys.stderr)
983
+ print(" got user" , file=sys.stderr)
981
984
return user
982
985
except ListUser.DoesNotExist:
983
- print(' new user' , file=sys.stderr)
986
+ print(" new user" , file=sys.stderr)
984
987
return ListUser.objects.create(email=token.email)
985
988
986
-
987
989
def get_user(self, email):
988
990
return ListUser.objects.get(email=email)
989
991
----
@@ -1006,54 +1008,56 @@ How about something like this?
1006
1008
1007
1009
1008
1010
[role="sourcecode"]
1009
- .src/accounts/tests/test_authentication.py
1011
+ .src/accounts/tests/test_authentication.py (ch19l024)
1010
1012
====
1011
1013
[source,python]
1012
1014
----
1013
- from django.test import TestCase
1014
1015
from django.contrib.auth import get_user_model
1016
+ from django.http import HttpRequest
1017
+ from django.test import TestCase
1018
+
1015
1019
from accounts.authentication import PasswordlessAuthenticationBackend
1016
1020
from accounts.models import Token
1021
+
1017
1022
User = get_user_model()
1018
1023
1019
1024
1020
1025
class AuthenticateTest(TestCase):
1021
-
1022
1026
def test_returns_None_if_no_such_token(self):
1023
1027
result = PasswordlessAuthenticationBackend().authenticate(
1024
- ' no-such-token'
1028
+ HttpRequest(), " no-such-token"
1025
1029
)
1026
1030
self.assertIsNone(result)
1027
1031
1028
-
1029
1032
def test_returns_new_user_with_correct_email_if_token_exists(self):
1030
-
1033
+
1031
1034
token = Token.objects.create(email=email)
1032
- user = PasswordlessAuthenticationBackend().authenticate(token.uid)
1035
+ user = PasswordlessAuthenticationBackend().authenticate(
1036
+ HttpRequest(), token.uid
1037
+ )
1033
1038
new_user = User.objects.get(email=email)
1034
1039
self.assertEqual(user, new_user)
1035
1040
1036
-
1037
1041
def test_returns_existing_user_with_correct_email_if_token_exists(self):
1038
-
1042
+
1039
1043
existing_user = User.objects.create(email=email)
1040
1044
token = Token.objects.create(email=email)
1041
- user = PasswordlessAuthenticationBackend().authenticate(token.uid)
1045
+ user = PasswordlessAuthenticationBackend().authenticate(
1046
+ HttpRequest(), token.uid
1047
+ )
1042
1048
self.assertEqual(user, existing_user)
1043
-
1044
1049
----
1045
1050
====
1046
1051
1047
1052
1048
- In 'authenticate.py' we'll just have a little placeholder:
1053
+ In _authenticate.py_ we'll just have a little placeholder:
1049
1054
1050
1055
[role="sourcecode"]
1051
1056
.src/accounts/authentication.py (ch19l025)
1052
1057
====
1053
1058
[source,python]
1054
1059
----
1055
1060
class PasswordlessAuthenticationBackend:
1056
-
1057
1061
def authenticate(self, request, uid):
1058
1062
pass
1059
1063
----
@@ -1062,31 +1066,35 @@ class PasswordlessAuthenticationBackend:
1062
1066
1063
1067
How do we get on?
1064
1068
1065
- [subs="specialcharacters, macros"]
1069
+ [subs="macros"]
1066
1070
----
1067
1071
$ pass:quotes[*python src/manage.py test accounts*]
1068
1072
1069
1073
.FE.........
1070
1074
======================================================================
1071
- ERROR: test_returns_new_user_with_correct_email_if_token_exists
1072
- (accounts.tests.test_authentication.AuthenticateTest)
1075
+ ERROR: test_returns_new_user_with_correct_email_if_token_exists (accounts.tests
1076
+ .test_authentication.AuthenticateTest.test_returns_new_user_with_correct_email_
1077
+ if_token_exists)
1073
1078
---------------------------------------------------------------------
1074
1079
Traceback (most recent call last):
1075
- File "...goat-book/accounts/tests/test_authentication.py", line 21 , in
1080
+ File "...goat-book/src/ accounts/tests/test_authentication.py", line 24 , in
1076
1081
test_returns_new_user_with_correct_email_if_token_exists
1077
1082
new_user = User.objects.get(email=email)
1083
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1078
1084
[...]
1079
- accounts.models.DoesNotExist: User matching query does not exist.
1085
+ accounts.models.User.DoesNotExist: User matching query does not exist.
1086
+
1080
1087
1081
1088
======================================================================
1082
- FAIL: test_returns_existing_user_with_correct_email_if_token_exists
1083
- (accounts.tests.test_authentication.AuthenticateTest)
1089
+ FAIL: test_returns_existing_user_with_correct_email_if_token_exists (accounts.t
1090
+ ests.test_authentication.AuthenticateTest.test_returns_existing_user_with_corre
1091
+ ct_email_if_token_exists)
1084
1092
---------------------------------------------------------------------
1085
1093
Traceback (most recent call last):
1086
- File "...goat-book/accounts/tests/test_authentication.py", line 30 , in
1094
+ File "...goat-book/src/ accounts/tests/test_authentication.py", line 34 , in
1087
1095
test_returns_existing_user_with_correct_email_if_token_exists
1088
1096
self.assertEqual(user, existing_user)
1089
- AssertionError: None != <User: User object>
1097
+ AssertionError: None != pass:specialcharacters[ <User: User object ([email protected] )>]
1090
1098
1091
1099
---------------------------------------------------------------------
1092
1100
Ran 12 tests in 0.038s
@@ -1104,6 +1112,7 @@ Here's a first cut:
1104
1112
----
1105
1113
from accounts.models import Token, User
1106
1114
1115
+
1107
1116
class PasswordlessAuthenticationBackend:
1108
1117
def authenticate(self, request, uid):
1109
1118
token = Token.objects.get(uid=uid)
@@ -1118,15 +1127,17 @@ That gets one test passing but breaks another one:
1118
1127
[subs="specialcharacters,macros"]
1119
1128
----
1120
1129
$ pass:quotes[*python src/manage.py test accounts*]
1121
- ERROR: test_returns_None_if_no_such_token
1122
- (accounts.tests.test_authentication.AuthenticateTest)
1123
1130
1124
- accounts.models.DoesNotExist: Token matching query does not exist.
1131
+ ERROR: test_returns_None_if_no_such_token (accounts.tests.test_authentication.A
1132
+ uthenticateTest.test_returns_None_if_no_such_token)
1133
+ [...]
1134
+ accounts.models.Token.DoesNotExist: Token matching query does not exist.
1125
1135
1126
- ERROR: test_returns_new_user_with_correct_email_if_token_exists
1127
- (accounts.tests.test_authentication.AuthenticateTest)
1136
+ ERROR: test_returns_new_user_with_correct_email_if_token_exists (accounts.tests
1137
+ .test_authentication.AuthenticateTest.test_returns_new_user_with_correct_email_
1138
+ if_token_exists)
1128
1139
[...]
1129
- accounts.models.DoesNotExist: User matching query does not exist.
1140
+ accounts.models.User. DoesNotExist: User matching query does not exist.
1130
1141
----
1131
1142
1132
1143
Let's fix each of those in turn:
0 commit comments