How to check if a user is logged in? Flask - python

i have a problem with a functionality of flask-login.
I need to create a system, that prevents multiple users from logging in on one account in the same time. The goal i am trying to achieve, is a way to check if the user is currently logged in, and deny access to people that are trying to log in if the account is already logged in. I was trying to use:
user.is_active
user.is_authenticated
But they always are displaying "True", here is the rest of the code: is there a property that changes after the users logs in/out?
def login():
if request.method == 'GET':
return render_template('login.html')
else:
login = request.form['login']
password = request.form['password'].encode('utf-8')
user = User.query.filter_by(username=f"{login}").first()
if user == None:
return "Non-Existing User"
else:
if bcrypt.checkpw(password,user.password.encode('utf-8')):
login_user(user)
return "Success"
else:
return "Bad creds."
#app.route('/logout')
#login_required
def logout():
logout_user()
return 'You are logged out'```

I don't know about any property but we can do it another way. You can store a token like thing in database with the user details.
class user(db.Model):
[...]
token = db.Column(db.String(20))
when the user login, you can generate a random hex or string and store it in database.
When user logout set token to False
while logging in the user , you can check if token is not False.
user = User.query.filter_by(username=user_input).first()
if user.token != False:
// allow user to login
else:
// don't allow him and show warning message.

Related

Reset password view without using FormViews in django

I am trying to set a reset password view without using the reset FormViews that Django uses by default. This means that I don't really use the auth application, more than for the tokens and some other small stuff.
What I did now is a normal view that displays an email/username form, and send an email to the user with a token:
password_reset_token = PasswordResetTokenGenerator()
def sendPasswordResetEmail(user, current_site):
mail_subject = 'Password reset'
message = render_to_string('myapp/password_reset_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': password_reset_token.make_token(user),
})
to_email = user.email
email = EmailMessage(mail_subject, message, from_email='testing#testing.com', to=[to_email])
email.send()
After this, the user should be displayed with a view that asks for the user to fill a SetPasswordForm if the token is correct and it's a GET request. Or it should check for the token and check if the form is valid. If the form and token are valid then the password should be changed.
I am trying to replicate a bit Django's PasswordResetConfirmView, but I'm not really sure if I'm doing it right. This is how I would do it, but I can't tell if there's any way to exploit the view somehow:
def passwordResetConfirm(request, uidb64, token):
if request.user.is_authenticated:
return redirect("myapp:index")
try:
uid = force_str(urlsafe_base64_decode(uidb64))
user = CustomUser.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, CustomUser.DoesNotExist):
user = None
if user is not None:
if password_reset_token.check_token(user, token):
if request.method == 'POST':
#TODO: Check SetPasswordForm is valid
#TODO: if form is not valid redirect to error url
#TODO: user = form.save()
#TODO: redirect to done url
pass
else:
return render(request, "myapp/password_reset_confirm.html")
return HttpResponse('Password reset link is invalid!')
Is this safe to do? I see in the PasswordResetConfirmView they perform some more redirections but I'm not sure what they are doing exactly.
Also, will these token expire? Or they remain there working forever? Meaning that if I request two reset password tokens and don't use them, if I use them after a few days, will they still be working?
Using Python3 and Django4. Also my website uses HTTPS everywhere.

user authentification failure despite successful login

The below login solution is not successfully authenticating the user.
After the login_user(user) function is called, the current_user is supposed to be authenticated.
When trying: print(flask_login.current_user.is_authenticated) immediately after login this returns TRUE, but as soon as the next page loads it returns FALSE.
In summary: The user authentification state is not persistent.
Consequently, pages protected with the #flask_login.login_required decorator (below the #app.route line) are inaccessible and I am redirected to the #login_manager.unauthorized_handler page.
As I understand it, the Flask framework is supposed to set cookies or send some kind of information in the headers that contain some kind of authentication. I also tried using the flask 'sessions' module and also tried using the 'g' module, but these produced entirely different errors.
The below version of the code I plagiarised from https://github.com/maxcountryman/flask-login, which uses only the things I have below. Yet for some reason, my version isn't working.
For the purposes of this testing phase, I made a list containing python dicts of a user so I don't have to make multiple unnecessary calls to the Firebase db I'm using to store the info.
This is the setup section for the login manager including my copy of the UserMixin class:
app.secret_key = 'dummysecretkey'
login_manager = flask_login.LoginManager()
login_manager.init_app(app)
class User(flask_login.UserMixin):
pass
This is a sample of the structure of the users:
{
'email': 'email#domain.com',
'password': 'password',
'username': 'user01'
...*other fields*...
}
Here are the routes for the login manager:
#login_manager.user_loader
def user_loader(username):
for entries in users:
if entries['username'] not in users:
return
for entries in users:
if entries['username'] == username:
user = User()
user.id = entries['username']
return user
#login_manager.request_loader
def request_loader(request):
username = request.form.get('username')
try:
for entries in users:
if entries['username'] == username:
user = User()
user.id = entries['username']
user.is_authenticated = request.form['password'] == entries['password']
return user
except:
return None
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
uname = request.form['uname']
psw = request.form['psw']
for entries in users:
if uname == entries['username'] and psw == entries['password']:
user = User()
user.id = uname
flask_login.login_user(user)
print(flask_login.current_user.is_authenticated)
return redirect(url_for('addnew'))
return 'Bad login'
Example route that requires authentication:
#app.route('/addnew')
#flask_login.login_required
def addnew():
return render_template("addnew.html")
Notwithstanding the flaws in the password comparison (I'm aware they're insecure), could someone please point out the flaw in the above code or present an alternative to achieve the login authentication?
I am bit confused by your code.
From the Flask Login documentation:
Sometimes you want to login users without using cookies, such as using header values or an api key passed as a query argument. In these cases, you should use the request_loader callback.
But I understand you want to use cookie based login?
So you should not use the request_loader.
Also, why do you instantiate a new User in the login route? The login should compare the login data with already existing users.
I suggest you "manually" instantiate the users and put them in a list like this:
users = []
a = User()
a.name = "name_a"
a.id = "id_a"
users.append(a)
...
And then adapt your user_loader to compare the login data from the form with the existing data.
There is an excellent Flask tutorial out there by Miguel Grinberg, which also explains the user login:
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

GitHub-Flask Authorize Scope Issue

I'm using Github-Flask to authenitcate users on my app. I use github.authorize(scope='user:email'). How can I get the logged in user's email?
github = GitHub(app)
user = None
#app.route('/login')
def login():
if user.username:
return redirect(url_for('index'))
return github.authorize(scope='user:email')
#github.access_token_getter
def token_getter():
if user is not None:
return user.github_access_token
#app.route('/github-callback')
#github.authorized_handler
def authorized(oauth_token):
if oauth_token is None:
flask.flash("Authorization failed.")
return redirect(url_for('index'))
global user
user.username = oauth_token
return redirect(url_for('index'))
The login route is only redirecting to GitHub's authorization page, it has no way to access the user data yet because the user isn't logged in. Once you get to the authorized callback, you can make API calls to GitHub.
In the authorized route, use github.get to call the user API endpoint.
data = github.get('user')
email = data['email']
Also, do not use global user to store the logged in user. See Are global variables thread safe in flask? Instead, store the user id in session, and load the user into g, as shown in GitHub-Flask's full example.

Django authentication seems to always return none

Django's authenticate function seems to always be returning none, ive already checked out this thread and updated the authentication backends in the settigns.py file.
This is the code that i am using to save the accounts being created:
if request.method == 'POST':
# Getting the information from the filled in UserCreationForm
user_form = UserCreationForm(data=request.POST)
# If the the form is valid then save the users data to the database
# hash the password using set_password and save the user again
# set registered to True
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors
# Not a HTTP POST, so these forms will be blank, ready for user input.
else:
user_form = UserCreationForm()
# Render the template depending on the context.
return render_to_response(
'contracts/register.html',
{'user_form': user_form, 'registered': registered}, context)
This seems to be working, since after i create a new user on the site, the access database its linked to updates with that username and the encrypted password.
The user_from is created from UserCreationForm which is:
class UserCreationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','password','first_name','last_name','email','is_staff','is_active')
Here is the code in my user_login method which should be grabbing the username and password from the request and authenticating the combo
def user_login(request):
# context for the user's request.
context = RequestContext(request)
# form = AuthenticationForm()
# If the request is a HTTP POST
if request.method == 'POST':
# Gather the username and password provided by the user.
# This information is obtained from the login form.
user = request.user
userSubmit = user.username
passSubmit = user.password
#username = request.POST.get['username']
#password = request.POST.get['password']
user = authenticate(username = userSubmit, password=passSubmit)
#try:
# user = authenticate(username=userSubmit, password=passSubmit)
#except LockedOut:
# messages.error(request, 'You have been locked out because of too many login attempts. Please try again in 10 minutes.')
# If we have a User object, the details are correct.
# If None (Python's way of representing the absence of a value), no user
# with matching credentials was found.
else:
if user:
# Is the account active? It could have been disabled.
if user.is_active:
# If the account is valid and active, we can log the user in.
# We'll send the user back to the homepage.
login(request, user)
return redirect('home')
else:
# An inactive account was used - no logging in!
messages.error(request, 'Your account is disabled.')
else:
messages.error(request, 'The credentials you entered are invalid.')
# Bad login details were provided. So we can't log the user in.
# The request is not a HTTP POST, so display the login form.
# This scenario would most likely be a HTTP GET.
# No context variables to pass to the template system, hence the
# blank dictionary object...
return render_to_response('administrative/login.html', {'form': form}, context)

Django User Authentication - Can't pass #login_required decorator

So I'm currently trying to implement an already existing application for payment processing via Braintree (https://github.com/Tivix/django-braintree for reference). It seems like all the meat of this application is placed at the /payments-billing/ directory but I can't seem to get into it to check it out. It seems like what's stopping me is a #login_required decorator placed just before the view since whenever I access the directory it sends me back to the defined LOGIN_URL. However I have set up a login feature at the LOGIN_URL that authenticates the user and then sends them to /payments-billing/ but it just redirects back again. Here is my code:
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')
Clearly the user is being authenticated and is active since it passes both tests when you try it, but it always just sends the user back to the LOGIN_URL rather than /payments-billing/. Anyone know what's the deal here?
The authenticate function doesn't log a user in, it just checks their username/password. You also have to call django.contrib.auth.login() to do the actual logging in. See the example in the documentation.
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
login(request, user)
### Now it should get redirected to /payments-billing/
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')

Categories