I am building the reset password page, the first page where the users enter his email work fine, he receive the reset password email with success. The problem it with the page where the user actually write his new password.
When I click on the link / go to the page it give me this error:
assert uidb64 is not None and token is not None # checked by URLconf
I am following this docs here: https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/views/
here is my views.py
#sensitive_post_parameters()
#never_cache
def password_reset_confirm(request, uidb64=None, token=None,
template_name='users/password_reset_confirm.html',
token_generator=default_token_generator,
set_password_form=SetPasswordForm,
post_reset_redirect=None,
current_app=None, extra_context=None):
"""
View that checks the hash in a password reset link and presents a
form for entering a new password.
"""
UserModel = get_user_model()
assert uidb64 is not None and token is not None # checked by URLconf
if post_reset_redirect is None:
post_reset_redirect = reverse('password_reset_complete')
else:
post_reset_redirect = resolve_url(post_reset_redirect)
try:
# urlsafe_base64_decode() decodes to bytestring on Python 3
uid = force_text(urlsafe_base64_decode(uidb64))
user = UserModel._default_manager.get(pk=uid)
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
validlink = True
title = ('Enter new password')
if request.method == 'POST':
form = set_password_form(user, request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(post_reset_redirect)
else:
form = set_password_form(user)
else:
validlink = False
form = None
title = ('Password reset unsuccessful')
context = {
'form': form,
'title': title,
'validlink': validlink,
}
if extra_context is not None:
context.update(extra_context)
if current_app is not None:
request.current_app = current_app
return TemplateResponse(request, template_name, context)
here is my urls.py
urlpatterns = [
path('password_reset/', views.password_reset, name='password_reset'),
path('password_reset/done/', views.password_reset_done, name="password_reset_done"),
path('reset/MTU/set-password/', views.password_reset_confirm, name="password_reset_confirm")
]
Related
I want to create a directory like website.com/user after the user get logged in!
And I'm not sure which url pattern in my app/urls.py should call this myfun to capture slug: user in url
def myfun(request, user):
user = TwitterUser().objects.get(user=user)
return render(request, 'authorization/home.html', {'user' : user})
models.py
class TwitterUser(models.Model):
screen_name = models.CharField(max_length=255)
name = models.CharField(max_length=255)
user = models.SlugField('auth.User', unique=True, null=True)
app/urls.py
urlpatterns = [
path('', views.index, name='index'),
path('twitter_login/', views.twitter_login, name='twitter_login'),
path('twitter_callback/', views.twitter_callback, name='twitter_callback'),
path('twitter_logout/', views.twitter_logout, name='twitter_logout'),
]
view.py
def twitter_login(request):
twitter_api = TwitterAPI()
url, oauth_token, oauth_token_secret = twitter_api.twitter_login()
if url is None or url == '':
messages.add_message(request, messages.ERROR, 'Unable to login. Please try again.')
return render(request, 'authorization/error_page.html')
else:
twitter_auth_token = TwitterAuthToken.objects.filter(oauth_token=oauth_token).first()
if twitter_auth_token is None:
twitter_auth_token = TwitterAuthToken(oauth_token=oauth_token, oauth_token_secret=oauth_token_secret)
twitter_auth_token.save()
else:
twitter_auth_token.oauth_token_secret = oauth_token_secret
twitter_auth_token.save()
return redirect(url)
def twitter_callback(request):
if 'denied' in request.GET:
messages.add_message(request, messages.ERROR, 'Unable to login or login canceled. Please try again.')
return render(request, 'authorization/error_page.html')
twitter_api = TwitterAPI()
oauth_verifier = request.GET.get('oauth_verifier')
oauth_token = request.GET.get('oauth_token')
twitter_auth_token = TwitterAuthToken.objects.filter(oauth_token=oauth_token).first()
if twitter_auth_token is not None:
access_token, access_token_secret = twitter_api.twitter_callback(oauth_verifier, oauth_token, twitter_auth_token.oauth_token_secret)
if access_token is not None and access_token_secret is not None:
twitter_auth_token.oauth_token = access_token
twitter_auth_token.oauth_token_secret = access_token_secret
twitter_auth_token.save()
# Create user
info = twitter_api.get_me(access_token, access_token_secret)
if info is not None:
twitter_user_new = TwitterUser(twitter_id=info[0]['id'], screen_name=info[0]['username'],
name=info[0]['name'], profile_image_url=info[0]['profile_image_url'])
twitter_user_new.twitter_oauth_token = twitter_auth_token
user, twitter_user = create_update_user_from_twitter(twitter_user_new)
if user is not None:
login(request, user)
return redirect('index')
else:
messages.add_message(request, messages.ERROR, 'Unable to get profile details. Please try again.')
return render(request, 'authorization/error_page.html')
else:
messages.add_message(request, messages.ERROR, 'Unable to get access token. Please try again.')
return render(request, 'authorization/error_page.html')
else:
messages.add_message(request, messages.ERROR, 'Unable to retrieve access token. Please try again.')
return render(request, 'authorization/error_page.html')
#login_required
#twitter_login_required
def index(request):
return render(request, 'authorization/home.html')
#login_required
def twitter_logout(request):
logout(request)
return redirect('index')
Your response will be highly appreciated :)
Add it to your urls.py with the relevant placeholder and get the placeholder as parameter in the view:
urlpatterns = [
path('', views.index, name='index'),
path('<str:user>', views.myfun, name='myfun')
]
You can see more info here in Django documentation https://docs.djangoproject.com/en/4.1/topics/http/urls/
I am working on a project and i am not using the default django user model instead i am using my own custom user model. but i am experiencing a problem. For my user model i have also made my own authb.py file which i have provided below and if i am using the default django authentication then it is authenticating only my superuser and not the user that i am entering through the sign up form and i am totally stuck.
first here is my authb.py
from .models import User
class AuthB:
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(username=username)
return user
except:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except:
return None
but right now i am not using this authb instead i am using default authentication.
here is my models.py for user model
class User(models.Model):
is_authenticated = True
username = models.CharField(max_length= 25)
email = models.CharField(max_length= 150)
password = models.CharField(max_length= 100)
last_login = models.DateTimeField(auto_now= True)
profilepic = models.CharField(max_length= 255, default= "")
def __str__(self):
return self.username
here is my views.py file
def signup(request):
# context = {}
# return render(request, 'sign-up.html', context)
if request.method == 'POST':
# print(request.POST)
# Get form values
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
# Check if passwords match
# Check Username
if User.objects.filter(username=username).exists():
return redirect('signup')
else:
if User.objects.filter(email=email).exists():
return redirect('signup')
else:
u = User.objects.create_user(username=username, password=password, email=email)
u.save()
return redirect('login')
else:
return render(request, 'sign-up.html')
def login(request):
# context = {}
# return render(request, 'index.html', context)
if request.method =='POST':
# print(request.POST)
email = request.POST['email']
password = request.POST['password']
u= auth.authenticate(email=email, password=password)
return redirect('index')
else:
return render(request, 'login.html')
The main problem is that simple user is not able to login in my website only admin are able to login and django i not authenticating my simple user.
I'm using the normal development server for Django and i am building a simple app.
A user should be able to log in and change his email and password.
To understand the django system better, I decided to write the views and such myself, only using the contrib.auth library.
Now to the problem:
Once a user logs in and changes his password, he cannot login again, unless he logs into the standard django admin page before.
Here is my code:
the views.py
def login(request):
print("test")
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
return HttpResponseRedirect('/accountManagement/home')
else:
form = LoginForm()
else:
HttpResponse("form is not valid")
else:
form = LoginForm()
return render(request, 'accountManagement/login.html', {'form': form})
def home(request):
print(request.user.username)
if request.user.is_authenticated:
passwordForm = ChangePasswordForm()
emailForm = ChangeEmailForm()
return render(request, 'accountManagement/home.html', {'passwordForm': passwordForm, 'emailForm': emailForm})
else:
return HttpResponseRedirect("/accountManagement/")
def change_password(request):
if request.user.is_authenticated:
if request.method == 'POST':
passwordForm = ChangePasswordForm(request.POST)
if passwordForm.is_valid():
oldPassword = passwordForm.cleaned_data['oldPassword']
newPassword = passwordForm.cleaned_data['newPassword']
newPasswordConfirmation = passwordForm.cleaned_data['newPasswordConfirmation']
if (newPassword == newPasswordConfirmation) and (request.user.check_password(oldPassword)):
request.user.set_password(newPassword)
request.user.save()
return HttpResponseRedirect("/accountManagement/logout")
else:
return HttpResponse("password change failed")
else:
return HttpResponse("password form not valid")
else:
return HttpResponse("request != POST")
else:
return HttpResponse("user ist not authenticated")
url.py:
urlpatterns = [
url(r'^$', views.login, name='login'),
url(r'^home', views.home, name='home'),
url(r'^changeEmail', views.change_email, name='changeEmail'),
url(r'^changePassword', views.change_password, name='changePassword'),
url(r'^logout', views.logout_view, name='logout'),
]
the forms:
class LoginForm(forms.Form):
username = forms.CharField(label='Username', max_length=20)
password = forms.CharField(label='Password', max_length=20)
class ChangeEmailForm(forms.Form):
newEmail = forms.CharField(label='New Email', max_length=50)
class ChangePasswordForm(forms.Form):
oldPassword = forms.CharField(label='Old Password', max_length=20)
newPassword = forms.CharField(label='New Password', max_length=20)
newPasswordConfirmation = forms.CharField(label='Confirm new Password', max_length=20)
Thanks for the help, really can't figure this one out.
Changing password destroy user authentication status, so you need re-authenticate him with new password again:
from django.contrib.auth import login
def change_password(request):
if request.user.is_authenticated:
if request.method == 'POST':
passwordForm = ChangePasswordForm(request.POST)
if passwordForm.is_valid():
oldPassword = passwordForm.cleaned_data['oldPassword']
newPassword = passwordForm.cleaned_data['newPassword']
newPasswordConfirmation =
passwordForm.cleaned_data['newPasswordConfirmation']
if (newPassword == newPasswordConfirmation)\
and (request.user.check_password(oldPassword)):
request.user.set_password(newPassword)
request.user.save()
# Re-authentication ===============================
# =================================================
user = authenticate(username=request.user.username,
password=NewPassword)
login(request, user)
# Why redirect to logout?!
return HttpResponseRedirect("/accountManagement/logout")
else:
return HttpResponse("password change failed")
else:
return HttpResponse("password form not valid")
else:
return HttpResponse("request != POST")
else:
return HttpResponse("user ist not authenticated")
Also I suggest you use CBV (Class based views) instead FBV (Function based views).
Any case you can use decorators #login_required and #require_http_methods in your view to remove is_authenticated and method != 'POST' logic.
from django.views.decorators.http import require_http_methods
from django.contrib.auth.decorators import login_required
#require_http_methods(["POST", ])
#login_required(redirect_field_name='my_redirect_field')
def change_password(request):
passwordForm = ChangePasswordForm(request.POST)
if passwordForm.is_valid():
oldPassword = passwordForm.cleaned_data['oldPassword']
newPassword = passwordForm.cleaned_data['newPassword']
newPasswordConfirmation =
passwordForm.cleaned_data['newPasswordConfirmation']
if (newPassword == newPasswordConfirmation)\
and (request.user.check_password(oldPassword)):
request.user.set_password(newPassword)
request.user.save()
# Re-authentication ===============================
# =================================================
user = authenticate(username=request.user.username,
password=NewPassword)
login(request, user)
# Why redirect to logout?!
return HttpResponseRedirect("/accountManagement/logout")
else:
return HttpResponse("password change failed")
else:
return HttpResponse("password form not valid")
I'm trying to get my userPass field to be hashed with PBKDF2PasswordHasher upon successful submission and when submitted to check if the userNm field, already exists or not.
I have a modelform:
class RegistrationForm(ModelForm):
userPass = forms.CharField(widget=forms.PasswordInput, label='Password')
class Meta:
model = Client
fields = ['userNm','userPass']
def clean_RegForm(self):
cleanedUserName = self.cleaned_data.get('userNm')
if Client.objects.filter(userNm=cleanedUserName).exists():
errorMsg = u"Error occurred."
raise ValidationError(errorMsg)
else:
return cleanedUserName
a hasher.py file to define a custom definition for PBKDF2PasswordHasher:
from django.contrib.auth.hashers import PBKDF2PasswordHasher
class PBKDF2PasswordHasher(PBKDF2PasswordHasher):
iterations = PBKDF2PasswordHasher.iterations * 100
a view
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
clearUserName = RegForm.cleaned_data['userNm']
clearPassNoHash = RegForm.cleaned_data['userPass']
clearPass = make_password(clearPassNoHash.encode("utf-8"),bcrypt.gensalt(14))
RegForm.save()
try:
return HttpResponseRedirect('/Newuser/?userNm=' + clearUserName)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
else:
RegForm = RegistrationForm()
return render(request, 'reuse/register.html', {
'RegForm': RegForm
})
settings.py has:
PASSWORD_HASHERS = (
'MyApp.hashers.MyPBKDF2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
)
It currently outputs the userNm on the next page, and saves both userNm and userPass to database, but the userPass is cleartext.
What am I doing wrong here? can someone help?
I am getting KeyError in my partial pipeline when I try to register with twitter accounts while facebook accounts work fine. This is odd because the same function is working fine with facebook users.
The error message is as below:
KeyError at /myapp/
'partial_pipeline'
at 'myapp_auth_form' and my code is:
settings.py
SOCIAL_AUTH_ENABLED_BACKENDS=('facebook','twitter',)
SOCIAL_AUTH_DEFAULT_USERNAME='new_social_auth_user'
...
TWITTER_CONSUMER_KEY = 'mytwitterconsumerkey'
TWITTER_CONSUMER_SECRET = 'mytwitterconsumersecret'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.misc.save_status_to_session',
'myapp.pipeline.has_email',
'myapp.pipeline.check_by_email',
'myapp.pipeline.redirect_to_form',
'myapp.pipeline.get_username',
'myapp.pipeline.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details'
)
myapp.pipeline
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from social_auth.models import UserSocialAuth
from registration.models import UserProfile
def has_email(details, user=None, *args, **kwargs):
"""Check if email is provided and ask for it otherwise
"""
if user:
return None
email = details.get('email')
if email:
kwargs['request'].session['saved_email'] = email
else:
session = kwargs['request'].session
email = session.get('saved_email')
if not email:
return HttpResponseRedirect(reverse('myapp_email_form'))
def check_by_email(details, user=None, user_exists=UserSocialAuth.simple_user_exists, *args, **kwargs):
"""Check if there's user with same email address and ask for its password to associate
"""
if user:
return None
session = kwargs['request'].session
email = session.get('saved_email')
if email:
if user_exists(username=email):
return HttpResponseRedirect(reverse('myapp_auth_form'))
def redirect_to_form(*args, **kwargs):
"""Redirect to get password if user is None
"""
session = kwargs['request'].session
if not session.get('saved_password') and not session.get('saved_nickname') and not session.get('saved_sex') and kwargs.get('user') is None:
return HttpResponseRedirect(reverse('social_auth_form'))
def get_username(details, user=None, *args, **kwargs):
"""Return an username for new user. Return current user username
if user was given.
Returns email address since myapp uses email for username
"""
if user:
return {'username': user.username}
username = details.get('email') or ''
return {'username': username}
def create_user(backend, details, response, uid, username, user=None, *args, **kwargs):
"""Create user and user profile. Depends on get_username pipeline."""
if user:
return {'user': user}
if not username:
return None
request = kwargs['request']
password = request.session.get('saved_password') or ''
user = UserSocialAuth.create_user(username=username, email=username, password=password)
nickname = request.session.get('saved_nickname') or ''
sex = request.session.get('saved_sex') or 'F'
profile = UserProfile.objects.create(user = user, nickname = nickname, sex = sex)
referee_nickname = request.session.get('saved_referee') or False
# if there was a recommender
if referee_nickname:
try:
referee_profile = UserProfile.objects.get(nickname=referee_nickname)
profile.referee = referee_profile.user
profile.save()
except UserProfile.DoesNotExist:
pass
return {
'user': user,
'is_new': True
}
views.py
from social_auth.utils import setting
from django.contrib.auth import authenticate, login
def myapp_email_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" If email is unprovided, ask for it
"""
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_email'] = email
backend = request.session[name]['backend']
return redirect('socialauth_complete', backend=backend)
else:
form = EmailForm()
email = request.session.get('saved_email') or ''
variables = RequestContext(request, {
'form': form,
'email': email,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/email_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../email_form.html', variables, context_instance=RequestContext(request))
def myapp_auth_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" If user's email is already registered to myapp, ask user for its password
"""
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data['username']
user = authenticate(username=email, password=form.cleaned_data['password'])
if user is not None:
if user.is_active:
login(request, user)
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_user'] = user
############################################
backend = request.session[name]['backend'] #<- I'm getting the KeyError at this point
############################################
return redirect('socialauth_complete', backend=backend)
else:
return HttpResponseRedirect(reverse('inactive_user'))
else:
form.non_field_errors = _('A user with such email and password does not exist.')
else:
form = LoginForm()
email = request.session.get('saved_email') or ''
variables = RequestContext(request, {
'form': form,
'email': email,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/auth_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))
def social_auth_form(request):
# if user is logged in already, redirect the user to home
if request.user.is_authenticated():
if request.GET.get('mobile', False):
return HttpResponseRedirect(reverse('m_home'))
return HttpResponseRedirect(reverse('home'))
""" Remedy form taking missing information during social authentication
"""
nickname = ''
sex = 'F'
if request.method == 'POST':
form = SocialRegistrationForm(request.POST)
if form.is_valid():
nickname = form.cleaned_data['nickname']
sex = form.cleaned_data['sex']
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_nickname'] = nickname
request.session['saved_sex'] = sex
request.session['saved_password'] = form.cleaned_data['password1']
backend = request.session[name]['backend']
return redirect('socialauth_complete', backend=backend)
else:
form = SocialRegistrationForm()
nickname = request.session.get('saved_username') or ''
sex = request.session.get('saved_gender') or 'F'
if sex == 'male':
sex = 'M'
elif sex == 'female':
sex = 'F'
variables = RequestContext(request, {
'form': form,
'nickname': nickname,
'sex': sex,
})
if request.is_mobile or request.GET.get('mobile', False):
return render_to_response('mobile/registration/social/social_form.html', variables, context_instance=RequestContext(request))
return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))
You need to add 'social_auth.backends.pipeline.misc.save_status_to_session' before each method that issues a redirect and halts the process. It works with Facebook because Facebook discloses email addresses, but Twitter doesn't. So, add that method before any entry that does a redirect, or call it within the pipeline code before doing the redirect.
(Just posting the comment as an answer so it can be selected)
You get the following error because you are trying to access the session name with this request.session[name]. That format is suppose to use in storing a session. To fix that,
name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_user'] = user
############################################
request.session['name'] = name
backend = request.session.get('name') // this is the session format in getting the data
############################################
return redirect('socialauth_complete', backend=backend)