I want to login with both and phone number in this DRF - python-3.x

I'm currently using a custom user model and can log in with my phone number. But now I want to log in with both phone and email. Please check the given code and let me know in the comments if any more details are needed. Thanks in advance.
class LoginSerializer(serializers.Serializer):
phone = serializers.CharField()
password = serializers .CharField()
def validate(self, data):
email = data. get ('email')
phone = data.get('phone')
password = data.get('password')
reg = False
print(phone, ",", password)
obj = CustomUser.objects.get(phone=phone)
if phone and password:
user = authenticate(username=obj.username, password=password)
if user:
data['user'] = user
print(user.id)
else:
msg = 'login failed'
raise exceptions.ValidationError(msg)
else:
msg = 'provide credientials'
raise exceptions.ValidationError(msg)
return data

I'm assuming you mean User could use email OR phone to login. Here are some feedback for your code:
password should be required=True
You should add the email field in the serializer. Like the phone field, it must be optional (required=False)
In validate, throw an error if neither email nor phone are provided
Also throw an error if BOTH are provided. It's email OR phone, not neither, not both.
Make sure to have a unique constraint in your User model for the email and phone field. If they are used for auth, no user should have the same email or phone
Then, fetch your user using either phone or email
If you use get, you can do a try/except block on the Model.DoesNotExists error. Otherwise, you can use filter and throw an error if you did not find exactly 1 user
If 1 user, keep going
If no user, invalid credentials
If several users, there's a huge problem in your DB
Assuming you found 1 user, try authenticate him
If success, return valid response
Else, return invalid creds
Do note that there are other ways of implementing this, like adding custom authentication backend as mentioned in the comments. But for now, those are some improvements you can make

Related

How to get User Email from User model in a function Django

Hi Iam newbie to Django,
I written an function to send email from any user who need to know more info about the trip.
I didn't know to how to collect posted user email id from user database. need help.
def PostDetailView(request, pk):
context = {}
context["data"] = Post.objects.get(id=pk)
if request.method == "POST":
name = request.POST['uName']
# phone = request.POST["phone"]
email = request.POST['uEmail']
desc = request.POST['uDes']
userEmail = I need to assign email id of this trip posted user
subject = 'Iam Interested in your Trip'
message = f'Hi Iam {name}, Iam Interested you trip. Please share more details on {email} {desc}'
email_from = email
recipient_list = [userEmail, ]
send_mail( subject, message, email_from, recipient_list, desc )
messages.success(request, 'Message Sent Successfully.')
return render(request, 'ads/detail.html',context)
return render(request, 'ads/detail.html',context)
Need help to fix this.
I think the posted user is the current authenticated user ?
so you can get email:
userEmail = request.user.email

Node.js backend - user login using AWS SDK and Amazon Cognito

Premise: I've only just started learning how to interact with AWS services and my knowledge of these is limited. I try my best to search the official documentation but, at times, it's either difficult to understand (for a novice) or some bits seem to be missing. Apologies in advance if I've missed something obvious!
I'm building a project where user will input data using a React frontend, this will be sent to a Node.js backend, and the backend will then communicate with the Cognito user pool using the SDK.
I have managed to set up routes for registration, confirmation and resend code using these API actions:
signUp
confirmSignUp
resendConfirmationCode
I don't seem to be able to find login-related actions (from basic login to mfa authentication etc.). The documentation mentions a hosted UI, but I want everything to be sent to my backend and use that to handle the flow.
What am I missing?
Thanks.
Here is this use case written using the AWS SDK for Python (Boto3) - not Node JS. (This example will be ported to other AWS SDKs soon).
It will point you in the right direction in terms of what methods to call and what request objects are needed.
There is an AWS CDK script that will setup the user pool for use with this code example here:
https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/resources/cdk/cognito_scenario_user_pool_with_mfa
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
"""
Purpose
Shows you how to use the AWS SDK for Python (Boto3) with Amazon Cognito to
do the following:
1. Sign up a user with a user name, password, and email address.
2. Confirm the user from a code sent in email.
3. Set up multi-factor authentication by associating an MFA application with the user.
4. Sign in by using a password and an MFA code.
5. Register an MFA device to be tracked by Amazon Cognito.
6. Sign in by using a password and information from the tracked device. This avoids the
need to enter a new MFA code.
This scenario requires the following resources:
* An existing Amazon Cognito user pool that is configured to allow self sign-up.
* A client ID to use for authenticating with Amazon Cognito.
"""
import argparse
import base64
import logging
import os
from pprint import pp
import sys
import webbrowser
import boto3
import qrcode
from warrant import aws_srp
from cognito_idp_actions import CognitoIdentityProviderWrapper
# Add relative path to include demo_tools in this code example without needing to set up.
sys.path.append('../..')
import demo_tools.question as q
logger = logging.getLogger(__name__)
# snippet-start:[python.example_code.cognito-idp.Scenario_SignUpUserWithMfa]
def run_scenario(cognito_idp_client, user_pool_id, client_id):
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
print('-'*88)
print("Welcome to the Amazon Cognito user signup with MFA demo.")
print('-'*88)
cog_wrapper = CognitoIdentityProviderWrapper(cognito_idp_client, user_pool_id, client_id)
user_name = q.ask("Let's sign up a new user. Enter a user name: ", q.non_empty)
password = q.ask("Enter a password for the user: ", q.non_empty)
email = q.ask("Enter a valid email address that you own: ", q.non_empty)
confirmed = cog_wrapper.sign_up_user(user_name, password, email)
while not confirmed:
print(f"User {user_name} requires confirmation. Check {email} for "
f"a verification code.")
confirmation_code = q.ask("Enter the confirmation code from the email: ")
if not confirmation_code:
if q.ask("Do you need another confirmation code (y/n)? ", q.is_yesno):
delivery = cog_wrapper.resend_confirmation(user_name)
print(f"Confirmation code sent by {delivery['DeliveryMedium']} "
f"to {delivery['Destination']}.")
else:
confirmed = cog_wrapper.confirm_user_sign_up(user_name, confirmation_code)
print(f"User {user_name} is confirmed and ready to use.")
print('-'*88)
print("Let's get a list of users in the user pool.")
q.ask("Press Enter when you're ready.")
users = cog_wrapper.list_users()
if users:
print(f"Found {len(users)} users:")
pp(users)
else:
print("No users found.")
print('-'*88)
print("Let's sign in and get an access token.")
auth_tokens = None
challenge = 'ADMIN_USER_PASSWORD_AUTH'
response = {}
while challenge is not None:
if challenge == 'ADMIN_USER_PASSWORD_AUTH':
response = cog_wrapper.start_sign_in(user_name, password)
challenge = response['ChallengeName']
elif response['ChallengeName'] == 'MFA_SETUP':
print("First, we need to set up an MFA application.")
qr_img = qrcode.make(
f"otpauth://totp/{user_name}?secret={response['SecretCode']}")
qr_img.save("qr.png")
q.ask("Press Enter to see a QR code on your screen. Scan it into an MFA "
"application, such as Google Authenticator.")
webbrowser.open("qr.png")
mfa_code = q.ask(
"Enter the verification code from your MFA application: ", q.non_empty)
response = cog_wrapper.verify_mfa(response['Session'], mfa_code)
print(f"MFA device setup {response['Status']}")
print("Now that an MFA application is set up, let's sign in again.")
print("You might have to wait a few seconds for a new MFA code to appear in "
"your MFA application.")
challenge = 'ADMIN_USER_PASSWORD_AUTH'
elif response['ChallengeName'] == 'SOFTWARE_TOKEN_MFA':
auth_tokens = None
while auth_tokens is None:
mfa_code = q.ask(
"Enter a verification code from your MFA application: ", q.non_empty)
auth_tokens = cog_wrapper.respond_to_mfa_challenge(
user_name, response['Session'], mfa_code)
print(f"You're signed in as {user_name}.")
print("Here's your access token:")
pp(auth_tokens['AccessToken'])
print("And your device information:")
pp(auth_tokens['NewDeviceMetadata'])
challenge = None
else:
raise Exception(f"Got unexpected challenge {response['ChallengeName']}")
print('-'*88)
device_group_key = auth_tokens['NewDeviceMetadata']['DeviceGroupKey']
device_key = auth_tokens['NewDeviceMetadata']['DeviceKey']
device_password = base64.standard_b64encode(os.urandom(40)).decode('utf-8')
print("Let's confirm your MFA device so you don't have re-enter MFA tokens for it.")
q.ask("Press Enter when you're ready.")
cog_wrapper.confirm_mfa_device(
user_name, device_key, device_group_key, device_password,
auth_tokens['AccessToken'], aws_srp)
print(f"Your device {device_key} is confirmed.")
print('-'*88)
print(f"Now let's sign in as {user_name} from your confirmed device {device_key}.\n"
f"Because this device is tracked by Amazon Cognito, you won't have to re-enter an MFA code.")
q.ask("Press Enter when ready.")
auth_tokens = cog_wrapper.sign_in_with_tracked_device(
user_name, password, device_key, device_group_key, device_password, aws_srp)
print("You're signed in. Your access token is:")
pp(auth_tokens['AccessToken'])
print('-'*88)
print("Don't forget to delete your user pool when you're done with this example.")
print("\nThanks for watching!")
print('-'*88)
def main():
parser = argparse.ArgumentParser(
description="Shows how to sign up a new user with Amazon Cognito and associate "
"the user with an MFA application for multi-factor authentication.")
parser.add_argument('user_pool_id', help="The ID of the user pool to use for the example.")
parser.add_argument('client_id', help="The ID of the client application to use for the example.")
args = parser.parse_args()
try:
run_scenario(boto3.client('cognito-idp'), args.user_pool_id, args.client_id)
except Exception:
logging.exception("Something went wrong with the demo.")
if __name__ == '__main__':
main()
# snippet-end:[python.example_code.cognito-idp.Scenario_SignUpUserWithMfa]

django authenticate not working with user created by api , only work with user created by admin

i'm trying to generated token after login using drf. i'm using emailbackend for login with email and password but its not working with user created by api and with user created by admin its working
backends.py:
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if user.check_password(password):
return user
return None
Token serializers:
class AuthCustomTokenSerializer(serializers.Serializer):
'''
Changing Token auth to use email instead username
'''
email = serializers.EmailField(label=_("Email"))
password = serializers.CharField(
label=_("Password",),
style={'input_type': 'password'},
trim_whitespace=False
)
def validate(self, attrs):
email = attrs.get('email')
password = attrs.get('password')
print(email, password)
if email and password:
user = authenticate(username=email, password=password)
print("this is user", user)
# The authenticate call simply returns None for is_active=False
# users. (Assuming the default ModelBackend authentication
# backend.)
if not user:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg, code='authorization')
else:
msg = _('Must include "username" and "password".')
raise serializers.ValidationError(msg, code='authorization')
attrs['user'] = user
return attrs
login view:
#csrf_exempt
#api_view(["POST"])
#permission_classes((AllowAny,))
def login(request):
serializer = AuthCustomTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, _ = Token.objects.get_or_create(user=user)
return Response({token: token.key}, status=status.HTTP_200_OK)
with admin login:
user login create by api:
register api:
Thanks, Great.
This means that authenticate(username=email, password=password) does not return a user.
Do you work with a degugger ? or may be add a
print(email, password) just after the auth call.
print what comes back from auth . print(authenticate(username=email, password=password))
My guess is that username is not email or somthing like that :)
Edit
How to debug:
login with admin user stop just before this line:
authenticate(username=email, password=password)
check and print the email and password
Do the same with API user check and print the email and password
see that values are the same .
login to django admin site check all premissions flag groups etc etc that are different between both users
try to login to admin page with the api user (set up the correct flags is_active etc)
try in the django manage.py shell or from admin user page to create new password for the api user and retest

How to show validation error for inactive user with some response code

I am trying to build custom user model in django-rest-framework. The problem which i am facing is how should i show the custom message with response code when the user is not activate.
Currently if the user provided the correct credentials but the account is not active then he is throwing error response code 400 with the validation error. Here is my code which I am using for the login validation.
class TokenAuthSerializer(serializers.Serializer):
email = serializers.CharField()
password = serializers.CharField(
style = {'input_type':'password'},
trim_whitespace = False
)
def validate(self,attrs):
email = attrs.get('email')
password = attrs.get('password')
user = authenticate(
request= self.context.get('request'),
email = email,
password = password
)
if not user:
msg = _('Unable to authenticate with given credentials')
raise serializers.ValidationError(msg, code = 'authorization')
attrs['user'] = user
return attrs
In views:
class CreateTokenAuthorization(ObtainAuthToken):
serializer_class = TokenAuthSerializer
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
How to override this method to get the proper response code for the user is not active. Thank you for looking over it.

how can repeat signup aws cognito [solve]

solve is here gist
when sign up in our app, sign up with aws cognito and send verify email with code.
if user close app not input verify, user have to re sign up. (saved in cognito userpool state UNCONFIRM)
and it occur two problem.
password may be changed (when re sign up)
renew verify code
my code is here python3 and warrant
#app.route('/signup/', methods=['POST'])
def signup():
u = Cognito(os.getenv('COGNITO_USER_POOL_ID'), os.getenv('COGNITO_CLIENT_ID'),
user_pool_region=os.getenv('COGNITO_REGION'))
u.add_base_attributes(name=user_name, email=user_email)
u.register(user_email, user_password)
return redirect(url_for('lobby'))
err code
botocore.errorfactory.UsernameExistsException: An error occurred (UsernameExistsException) when calling the SignUp operation: An account with the given email already exists.
how to re signup with renew password, and send new verify email
Thanks
oh, i solve
#app.route('/signup/', methods=['POST'])
def signup():
idp_client = boto3.client('cognito-idp')
'''
resp = idp_client.sign_up(ClientId=app_client_id,
Username=user_email,
Password=user_password,
UserAttributes=[{'Name': 'email', 'Value': user_email}])
'''
resp = idp_client.resend_confirmation_code(ClientId=os.getenv('COGNITO_CLIENT_ID'),
Username=user_email)
print(resp) #check result
return redirect(url_for('lobby'))
use boto3 i want (resend not acquire password)

Resources