Django rest framework Logout and Login View don't work - authentication

I'm doing a user registration via email with email confirmation. Then user gets a email letter to activate and finish its registration, login methods works. But I cant logout that user, and log him again. Could you suggest any other methods got logout and login with similar register View.
Here is my RegisterView, that works good.
class RegisterView(APIView):
permission_classes = [AllowAny]
def post(self, request, *args, **kwargs):
email = request.data.get('email', False)
password = request.data.get('password', False)
role = request.data.get('role')
if email and password and role:
user = User.objects.filter(email=email)
if user.exists():
return JsonResponse('Такой email уже существует', safe=False)
else:
temp_data = {
'email': email,
'password': password,
'role': role
}
serializer = CreateUserSerializer(data=temp_data)
serializer.is_valid(raise_exception=True)
user.is_active = False
user = serializer.save()
# user = authenticate(request, email=email, password=password)
user.set_password(user.password)
user.save()
current_site = get_current_site(request)
print(current_site)
subject = 'Activate Your MySite Account'
message = render_to_string('account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user),
})
print(message)
from_email = settings.EMAIL_HOST_USER
to_email = serializer.validated_data.get('email')
email = EmailMessage(
subject, message, from_email, to=[to_email],
)
print(email)
email.send()
# return Response(serializer.data, status=status.HTTP_201_CREATED)
return HttpResponse('Please confirm your email address to complete the registration')
else:
return JsonResponse('Email не указан', safe=False)
Here is function for registration activating
def activate(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.set_password(user.password)
user.save()
login(request, user)
return HttpResponse('Thank you')
else:
return HttpResponse('Activation link is invalid!')
But my logout and login views dont work
class LogoutView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated,]
def post(self, request):
# django_logout(request)
request.user.auth_token.delete()
return Response(status=204)
class LoginView(KnoxLoginView):
permission_classes = (AllowAny,) #условие, если email не подтвержден, не поулчится залогиниться
def post(self, request, format=None):
serializer = LoginSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
# token, created = Token.objects.get_or_create(user=user)
# return Response({"token": token.key, 'id': token.user.id}, status=200)
login(request, user)
return super().post(request, format=None)
class LoginSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField(style={'input_type': 'password'}, trim_whitespace=False)
def validate(self, data):
email = data.get('email')
print(email)
password = data.get('password')
if email and password:
if User.objects.filter(email=email).exists():
print(email, password)
user = authenticate(request=self.context.get('request'), email=email, password=password)
print(user)
else:
msg = {
'status': False,
'detail': 'Email is not found'
}
raise serializers.ValidationError(msg)
if not user:
msg = {
'status': False,
'detail': 'Эмейлы не совпадают'
}
raise serializers.ValidationError(msg, code='authorization')
else:
msg = {
'status': False,
'detail': 'Email is not found in request'
}
raise serializers.ValidationError(msg, code='authorization')
data['user'] = user
return data

Related

Got AttributeError when attempting to get a value for field `email` on serializer `LoginSerializer`

Creating a Django API and want to login the user, the login is working but the exceptions not so much.
It was working until i wanted to return status
AttributeError at /login/
Got AttributeError when attempting to get a value for field email on serializer LoginSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Response instance.
Original exception text was: 'Response' object has no attribute 'email'.
I saw a few answers but the context didnt match.
What am i missing or doing wrong?
class LoginSerializer(serializers.ModelSerializer):
email = serializers.EmailField()
password = serializers.CharField(max_length=68, min_length=6, write_only = True)
username = serializers.CharField(
read_only=True
)
tokens = serializers.CharField(max_length=68, min_length=6, read_only=True)
class Meta:
model=User
fields = ['email', 'username', 'password', 'tokens']
def validate(self, attrs):
email = attrs.get('email', '')
password = attrs.get('password', '')
user = auth.authenticate(email=email, password=password)
if user is None:
return Response({'msg':'No such user'}, status=status.HTTP_401_UNAUTHORIZED)
# raise AuthenticationFailed({'status':False,'message': ' username is worng'}, status=status.HTTP_401_UNAUTHORIZED)
if not user.is_active:
raise AuthenticationFailed({'msg':'Account is disabled'})
if not user.is_verified:
raise AuthenticationFailed({'msg': 'Email is not verified'})
if not user:
return Response({'msg':'Invalid credentials, try again'}, status=status.HTTP_401_Unauthorized)
return{
'email':user.email,
'username':user.username,
'tokens':user.tokens()
}
return super.validate(attrs)
'views.py'
class LoginAPIView(APIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception = True)
return Response(serializer.data, status=status.HTTP_200_OK)
custom user model
class UserManager(BaseUserManager):
def create_user(self, username, email, password):
if username is None:
raise TypeError("User should be provide username")
if email is None:
raise TypeError("User should be provide email")
if password is None:
raise TypeError("User should be provide password")
user = self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password):
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=255, db_index=True)
email = models.EmailField(max_length=255, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
# is_authenticated = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}
def validate(self, attrs):
email = attrs.get('email')
password = attrs.get('password')
user = auth.authenticate(email=email, password=password)
print (user)
if not user:
raise AuthenticationFailed({'msg': 'No such user'}, code=status.HTTP_401_UNAUTHORIZED)
if user is None:
raise AuthenticationFailed({'message': ' Your Email or Password is wrong'}, code=status.HTTP_401_UNAUTHORIZED)
# raise AuthenticationFailed({'message': ' username is wrong'})
if not user.is_active:
raise AuthenticationFailed({'msg':'Account is disabled'},code=status.HTTP_403_FORBIDDEN)
if not user.is_verified:
raise AuthenticationFailed({'msg': 'Email is not verified'}, code=status.HTTP_401_UNAUTHORIZED)
This did the job for me. I guess the error came because the 'auth' did not take 'Response'

Django channels without redis

I have a django app based on this tutorial that works perfectly. It uses Redis in the Channel layers
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
The problem I have is that my web hosting provider will not allow Redis (unless I pay ££££).
Every example that I can find uses Redis in this role. Is there an alternative I could use?
there are a few options.
you can run your channel layer on a different service to were the main instance runs. AWS ElastiCache or many other redis hosts out there.
There is also a RabbitMQ channel layer but if your hosting provider charges a lot for reddis i expect they will also charge a lot for this ... https://github.com/CJWorkbench/channels_rabbitmq/
It turned out that channels is a non-starter on an affordable web-hosting platform. So I reverted to using Ajax and long polling. My application is based on this Django Tutorial.
models.py
class Message(models.Model):
room_name = models.CharField(null=False, blank=False, max_length=50)
sender = models.CharField(null=False, blank=False, max_length=50, default='Sender username')
datetime = models.DateTimeField(null=True, auto_now_add=True)
type = models.IntegerField(null=True, blank=True)
text = models.CharField(null=False, blank=False, max_length=250, default='message text')
context = models.TextField(null=True, blank=True)
urls.py
urlpatterns = [
path('<str:partner_pk>/check-message', views.CheckMessage.as_view(), name="check-message"),
path('<str:partner_pk>/send-message/<str:chat_text>', views.SendMessage.as_view(), name="send-message"),
]
views.py
class CheckMessage(View):
"""Duo check message."""
def get(self, request, partner_pk):
"""Render the GET request."""
pair, room_name = sort_pair(partner_pk, request.user.pk)
partner = User.objects.get(pk=partner_pk)
profile = get_object_or_404(Profile, user=request.user)
message = Message.objects.filter(room_name=room_name, sender=partner.username).earliest('datetime')
context = {'type': -1}
context = json.loads(message.context)
context['sender'] = message.sender
context['datetime'] = message.datetime
context['message_type'] = message.type
context['text'] = message.text
context['seat'] = profile.seat
message.delete()
return JsonResponse(context, safe=False)
class SendMessage(View):
def get(self, request, partner_pk, chat_text):
message_type = app.MESSAGE_TYPES['chat']
send_message(request, partner_pk, message_type, text=chat_text, context={})
return JsonResponse({}, safe=False)
chat.js
window.setInterval(checkMessage, 3000);
function checkMessage () {
$.ajax(
{
type:"GET",
url: "check-message",
cache: false,
success: function(message) {
processMessage(message);
}
}
)
}
// Take action when a message is received
function processMessage(context) {
switch (context.message_type) {
case 0:
sendMessage(context)
functionOne()
break;
case 1:
sendMessage(context)
functionTwo()
break;
case 2:
sendMessage(context)
functionThree()
break;
}
}
// Send a message to chat
function sendMessage (context) {
if (context.sender != username) {
var messageObject = {
'username': context.sender,
'text': context.text,
};
displayChat(context);
}
}
// Display a chat message in the chat box.
function displayChat(context) {
if (context.text !== '') {
var today = new Date();
var hours = pad(today.getHours(), 2)
var minutes = pad(today.getMinutes(), 2)
var seconds = pad(today.getSeconds(), 2)
var time = hours + ":" + minutes + ":" + seconds;
var chat_log = document.getElementById("chat-log");
chat_log.value += ('('+time+') '+context.sender + ': ' + context.text + '\n');
chat_log.scrollTop = chat_log.scrollHeight;
}
}
//pad string with leading zeros
function pad(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
// Call submit chat message if the user presses <return>.
document.querySelector('#chat-message-input').focus();
document.querySelector('#chat-message-input').onkeyup = function (e) {
if (e.keyCode === 13) { // enter, return
document.querySelector('#chat-message-submit').click();
}
};
// Submit the chat message if the user clicks on 'Send'.
document.querySelector('#chat-message-submit').onclick = function (e) {
var messageField = document.querySelector('#chat-message-input'), text = messageField.value, chat_log = document.getElementById("chat-log");
context = {sender: username, text: messageField.value}
displayChat(context)
sendChat(messageField.value)
chat_log.scrollTop = chat_log.scrollHeight;
messageField.value = '';
};
// Call the send-chat view
function sendChat(chat_text) {
$.ajax(
{
type:"GET",
url: "send-message/"+chat_text,
cache: false,
}
)
}

How to get logged username in template

I am using Django 1.8 with Python 3.4
I had no idea why my template doesn't show my username on template profile.html :/
profile.py
{% load staticfiles %}
<link rel="stylesheet" type="text/css" href="{% static 'accounts/css/style.css' %}" />
{% block content %}
<h2>My profile</h2>
<p>{{ request.user.username }}</p>
{% endblock %}
views.py
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from django.contrib.auth import authenticate, login
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/accounts/profile')
else:
# Return a 'disabled account' error message
...
pass
else:
# Return an 'invalid login' error message.
pass
form = AuthenticationForm()
args = {}
args.update(csrf(request))
args['form']= AuthenticationForm()
return render_to_response('accounts/login.html', args)
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
print(request.user)
if user.is_active:
login(request, user)
return HttpResponseRedirect('/accounts/profile')
else:
# Return a 'disabled account' error message
...
else:
# Return an 'invalid login' error message.
...
def profile(request):
username = request.user.username
return render_to_response('accounts/profile.html', username)
def register_user(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/register_success')
args = {}
args.update(csrf(request))
args['form']= UserCreationForm()
return render_to_response('accounts/register_user.html', args)
def register_success(request):
return render_to_response('accounts/register_success.html')
What's the best way to get user information from a django template?
Add django.template.context_processors.request to context_processors options of TEMPLATE variable in your settings.py file :
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request', # add this line
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

huawei api sms documentation

any one have the huawei SMS API documentation? (api/sms/sms-list)
I need to know how to talk with this API to get the SMS list:
It must be something like this:
<request>
<PageIndex>1</PageIndex>
<ReadCount>20</ReadCount>
<BoxType>1</BoxType>
<SortType>0</SortType>
<Ascending>0</Ascending>
<UnreadPreferred>0</UnreadPreferred>
</request>
But I got only a error code 100003 as answer. And I don't what that mean.
Thank You,
michel
I have done this on an Huawei E5221 with Python. The error you are getting is because you are not authenticated and need to login first. Then the list can be retrieved.
Also note that all API requests are POST's and not GET's.
Method to login:
def LoginToSMSGateway(sms_gateway_ip, username, password):
api_url = '/api/user/login'
post_data = '<request><Username>'+username+'</Username><Password>'+ base64.b64encode(password) +'</Password>'
r = requests.post(url='http://' + sms_gateway_ip + api_url, data=post_data)
if r.status_code == 200:
result = False
root = ET.fromstring(r.text)
for results in root.iter('response'):
if results.text == 'OK':
result = True
return result
else:
return False
Method to retrieve SMS List (The method will turn the XML results into a Python list of SMS's):
def GetSMSList(sms_gateway_ip):
class SMS:
Opened = False
Message = ''
api_url = '/api/sms/sms-list'
post_data = '<?xml version="1.0" encoding="UTF-8"?><request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>1</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>0</UnreadPreferred></request>'
headers = {'Referer': 'http://' + sms_gateway_ip + '/html/smsinbox.html'}
r = requests.post(url='http://' + sms_gateway_ip + api_url, data=post_data, headers=headers)
root = ET.fromstring(r.text)
resultsList = list()
for messages in root.iter('Messages'):
for message in messages:
sms = SMS()
sms.Message = message.find('Content').text
sms.Opened = False if message.find('SmsType').text == '1' else True
resultsList.append(sms)
return resultsList
To use it(The IP and credentials are the default values and need to be secured.) :
if LoginToSMSGateway('192.168.1.1', 'admin', 'admin'):
print 'Logged in.'
smsList = GetSMSList('192.168.1.1')
for sms in smsList:
print sms.Message
Since this the subject has been posted I think the API has changed a bit.
To get the SMS list, no need to login but you do need to get a sessionID and the corresponding Token. You can use that Method to get them.
def GetTokenAndSessionID(sms_gateway_ip):
url = '/html/smsinbox.html'
r = requests.get(sms_gateway_ip + url)
Setcookie = r.headers.get('set-cookie')
sessionID = Setcookie.split(';')[0]
token = re.findall(r'"([^"]*)"', r.text)[2]
return token, sessionID
And then the Method to get the sms list (It's using the first Method to wrap the sessionID and the Token in the headers).
def GetSmsList(sms_gateway_ip):
class SMS:
Opened = False
Message = ''
url = '/api/sms/sms-list'
token,sessionID = GetTokenAndSessionID(sms_gateway_ip)
post_data = '<request><PageIndex>1</PageIndex><ReadCount>20</ReadCount><BoxType>2</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>0</UnreadPreferred></request>'
headers = { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'__RequestVerificationToken': token,
'Cookie': sessionID
}
r = requests.post(sms_gateway_ip + url, data = post_data, headers=headers)
root = ET.fromstring(r.text)
resultsList = list()
for messages in root.iter('Messages'):
for message in messages :
sms = SMS()
sms.Message = message.find('Content').text
sms.Opened = False if message.find('SmsType').text == '1' else True
resultsList.append(sms)
To use it you just need to call it with the ip of the sms gateway: 192.168.8.1
GetSmsList(sms_gateway_ip)
Similar Code in Java hereunder using Apache HTTP Client classes
CloseableHttpClient httpclient = HttpClients.createDefault();
// 1. Have apache HTTPClient manage the cookie containing the SessionID
CookieStore cookieStore = new BasicCookieStore();
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
// 2. Extract the token
String token = "";
HttpGet hget = new HttpGet("http://192.168.8.1/html/smsinbox.html");
CloseableHttpResponse getRespo = httpclient.execute(hget, httpContext);
try {
StatusLine statusLine = getRespo.getStatusLine();
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
HttpEntity entity = getRespo.getEntity();
if (entity == null) {
throw new ClientProtocolException("Get response contains no content");
}
long len = entity.getContentLength();
StringTokenizer st = null;
if (len != -1 && len > 250) {
st = new StringTokenizer(EntityUtils.toString(entity).substring(0, 250), "\"");
}
int i = 1;
while (st != null && st.hasMoreTokens()) {
if (i++ == 10) {
token = st.nextToken();
break;
} else {
st.nextToken();
}
}
} finally {
getRespo.close();
}
System.out.println("Token: " + token);
// 3. Get the SMS messages using the Token
HttpPost hpost = new HttpPost("http://192.168.8.1/api/sms/sms-list");
String xmlRequest = "<request><PageIndex>1</PageIndex><ReadCount>1</ReadCount><BoxType>1</BoxType><SortType>0</SortType><Ascending>0</Ascending><UnreadPreferred>1</UnreadPreferred></request>";
StringEntity reqEntity = new StringEntity(xmlRequest);
reqEntity.setContentType("text/xml");
hpost.setEntity(reqEntity);
hpost.addHeader("__RequestVerificationToken", token);
CloseableHttpResponse postRespo = httpclient.execute(hpost, httpContext);
try {
StatusLine statusLine = postRespo.getStatusLine();
if (statusLine.getStatusCode() >= 300) {
throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase());
}
HttpEntity entity = postRespo.getEntity();
if (entity == null) {
throw new ClientProtocolException("Response contains no content");
}
System.out.println(EntityUtils.toString(entity));
//Your further processing here.
} finally {
postRespo.close();
}

Mock Grails Spring Security Logged in User

Looking for a way to mock spring security in some unit/integration tests.
Grails: V2.1.0
Spring Security Core: V1.2.7.3
Controller has the following:
// some action
def index(){
def user = getLoggedInUser()
render ....
}
...
private getLoggedInUser(){
return User.get(springSecurityService.principal.id)
}
I tried the following and various other ways but can't see to get it to work:
void testSomething(){
def dc = new SomeController()
dc.springSecurityService = [
encodePassword: 'password',
reauthenticate: { String u -> true},
loggedIn: true,
principal: [username:"Bob"]]
dc.index()
... assertion....
It seems that the user is not getting created and can't get the principal.id. Any suggestions or better alternatives?
I think the user is just being created, but not saved, and that's why it doesn't have an ID.
The solution could be this:
void testSomething(){
def dc = new SomeController()
def loggedInUser = new User(username: "Bob").save() // This way the user will have an ID
dc.springSecurityService = [
encodePassword: 'password',
reauthenticate: { String u -> true},
loggedIn: true,
principal: loggedInUser]
dc.index() ... assertion....
There's an alternative:
void testSomething(){
def dc = new SomeController()
def loggedInUser = new User(...).save()
dc.metaClass.getLoggedInUser = { loggedInUser }
...
I would suggest a refactor to getLoggedInUser:
private getLoggedInUser(){
return springSecurityService.currentUser
}
With this change, you could write:
void testSomething(){
def dc = new SomeController()
def loggedInUser = new User(...).save()
dc.springSecurityService = [
encodePassword: 'password',
reauthenticate: { String u -> true},
loggedIn: true,
getCurrenUser: { loggedInUser }]
...