Tuesday, January 22, 2019

use of decorator for authorization, multiple user access control in django python

You may have need authorization of multiple users i.e. specified user is provided access to special feature of an app,
let us say,
owner can create update delete data where  staff can only view and edit the data stored by owner.
For handling such king of requirements in python there is much easier and secure way of doing.

lets go through it now.

create decorators.py  inside the app where you need to authorize multiple user with multiple functionality.

inside decoratrs.py


from django.core.exceptions import PermissionDenied
from hotel.models import Hotels
def hotel_create_decorator(function):
def wrap(request, *args, **kwargs):
if request.user.is_hotel_owner==True:
return function(request, *args, **kwargs)
else:
raise PermissionDenied
return wrap

def hotel_update_decorator(function):
def wrap(request, *args, **kwargs):
entry = Hotels.objects.get(pk=kwargs['pk'])
if request.user.is_hotel_staff==True
and entry.owner_id_id == request.user.owner_id_id:
return function(request, *args, **kwargs)
else:
raise PermissionDenied
return wrap

here to update if the requested user is staff and if owner of the hotel is associated with the owner_id_id of the staff table then that staff can update the information about the hotel,

and for create:
if the logged in user is the owner then they can create the hotel

Now ,

inside views.py of teh app :

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from hotel.decorators import hotel_update_decorator
from hotel.decorators import hotel_delete_decorator

@method_decorator([login_required],name='dispatch')
class HotelDetail(DetailView):
model=Hotels
template_name='hotel/show.html'
queryset=Hotels.objects.all()


@method_decorator(login_required,name='dispatch')
@method_decorator(hotel_update_decorator,name='dispatch')
class HotelUpdate(SuccessMessageMixin,UpdateView):
template_name='hotel/create.html'
model=Hotels
form_class=HotelForm
success_message='Information Updated Successfully'
success_url=reverse_lazy('hotelindex')
queryset=Hotels.objects.all()

def form_invalid(self,form):
messages.warning(self.request,form.errors)
return self.render_to_response(self.get_context_data(object=form.data))
def get_context_data(self, **kwargs):
context = super(HotelUpdate, self).get_context_data(**kwargs)
context['owners'] = HotelOwner.objects.all().order_by('id').reverse()
return context


here, @method_decorator(hotel_update_decorator,name='dispatch')
refers to the hotel_update_decorator function of the decorators.py , if the condition inside of the function i.e.(hotel_update_decorator) all are satisfied then you will be able to update , else you will obtain forbidden message.

here, in the above code  you have seen
@method_decorator(login_required,name='dispatch')

this refers that: login is required , write this kine at the top of the class where you feels it is nessary to be logged in for accessing that feature of the app.


another way:
inside urls.py

from django.contrib.auth.decorators import login_required
path('', login_required(views.HotelListView.as_view()), name="hotelindex"),


Simply this is done now,



reset password , update password of logged in user

After user is logged in to the system they can update there password, this is the scenario now, lets start to dig in to the process:

after logged in , inside dash board :
somewhere you like ,
<a class="nav-link" href="{%url 'reset_account_password' %}"> Reset Password</a>

define the url in urls.py
path('ResetPassword/',views.reset_account_password,name="reset_account_password"),

Now, inside views.py
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode

def reset_account_password(request):
user=request.user
pwtoken=PasswordResetTokenGenerator().make_token(user)
newuid=urlsafe_base64_encode(force_bytes(user.pk)).decode()
return redirect('password_reset_confirm',uidb64=newuid,token=pwtoken)

For using this you need to import above lines in views.py

Its done , Simplest and secure way for doing ,
If you have any confussion then please leave comment below:

Monday, January 21, 2019

User login email verification in python with reset password after successful verification

When you really need more security while making accounts and secure registration towards the system you actually need is to authenticate email address via email:

Before going through this one: please kindly visit the following blog , so that you will be a be more clear , 
# IMPORTANT

But if you want direct coding here is how this is done, :

Lets start from beginning :

lets setup email first:

inside settings.py:

EMAIL_USE_TLS=True
EMAIL_HOST='smtp.gmail.com'
EMAIL_HOST_USER='youremail'
EMAIL_HOST_PASSWORD='yourpassword'
EMAIL_PORT=587


create app account and setup basics : go to link provided above for detail:

now inside forms.py of the account app:

from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from account.models import User
from hotel.owner.models import HotelOwner
from hotel.staff.models import HotelStaff

class HotelOwnerSignUpForm(UserCreationForm):
email=forms.EmailField(required=True,label='Email')
first_name=forms.CharField(required=True,label='First Name')
last_name=forms.CharField(required=True,label='Last Name')
class Meta(UserCreationForm.Meta):
model=User
fields=("first_name","last_name","email","username","password1","password2")

class HotelStaffSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model=User
fields=("first_name","last_name","email","username","password1","password2")

create tokens.py inside account app

from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) +
six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()  


Now inside urls.py  of account app


path('ResetPassword/',views.reset_account_password,name="reset_account_password"),
url(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',views.activate, name='activate'),

Inside views.py of account app
from django.shortcuts import render
from django.shortcuts import redirect
from django.views.generic import CreateView
from .forms import HotelOwnerSignUpForm
from .forms import HotelStaffSignUpForm
from django.http import HttpResponse
from account.models import User
from hotel.owner.models import HotelOwner

from django.contrib.auth import login, authenticate
from django.contrib.sites.shortcuts import get_current_site
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from .tokens import account_activation_token
from django.core.mail import EmailMessage
from django.contrib.auth.tokens import PasswordResetTokenGenerator

def signup(request):
if request.method == 'POST':
form = HotelOwnerSignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activate your blog account.'
message = render_to_string('account/active_email.html', {
'user': user,
'domain': current_site.domain,
'uid':urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token':account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return HttpResponse('Please confirm your email address to complete the registration')
else:
form = HotelOwnerSignUpForm()
return render(request, 'account/signup_form.html', {'form': form})

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.save()
owner=HotelOwner.objects.create(user=user)
id=user.id
login(request, user)
pwtoken=PasswordResetTokenGenerator().make_token(user)
newuid=urlsafe_base64_encode(force_bytes(user.pk)).decode()
return redirect('password_reset_confirm',uidb64=newuid,token=pwtoken)
#return redirect('hotel:ownerupdate',id)
else:
return HttpResponse('Activation link is invalid!')

class HotelStaffSignUpView(CreateView):
model = User
form_class = HotelStaffSignUpForm
template_name = 'account/signup_form.html'
# print(request.user)

def form_valid(self, form):
# user = form.save()
user=form.save(commit=False)
user.is_hotel_staff=True
user.save()
owner_id=self.request.user.id
staff=HotelStaff.objects.create(user=user,owner_id_id=owner_id)
id=user.id
return redirect('hotel:staffupdate',id)



here, after you fillup signup form it, will send email a link of password reset form and on clicking that password can be changed.

now , tehre is just few steps to follow:

create active_email.html inside templates of account app and:

Hi {{ user.username }},
Please click on the link to confirm your registration,
http://{{ domain }}{% url 'activate' uidb64=uid token=token %}

this is the message you are sending to the email obtained form signup form :

all about signup forms are described on the previous blog and link of blog is provided above.



This is all we need for email verification in python django project