handlers:
- url: /secure_api/.*
script: _go_app
login: required
auth_fail_action: unauthorized
This code only brings me to a page saying "Login required to view page." Is there a way to instead redirect to my home page?
When you specify auth_fail_action: unauthorized, you get the page you are seeing (see here for the details). Changing unauthorized to redirect will take them to the login screen, but if you want to do more granular handling of users based on their logged-in status, your best bet is to do it inside of your code via the Users API. For instance (this is adapted from the docs), here is a simple example that would redirect a non-logged-in user to /:
from google.appengine.api import users
import webapp2
class MyHandler(webapp2.RequestHandler):
def get(self):
user = users.get_current_user()
if user:
# Do stuff here for logged-in users
else:
# Redirect if user is None, which is the case for non-logged-in users
self.redirect('/')
Related
The Problem
I am trying to connect a superuser to the Django test client, and then access a page in the Django administration interface with a GET method. However, I get a redirect to the login page, even though the superuser is properly logged in.
The Code
def test(self) -> None:
client = Client()
user = User.objects.create(username='user', is_superuser=True)
client.force_login(user)
response = client.get(f'/admin/management/establishment/', follow=True)
print("Redirect chain\t", response.redirect_chain)
print("Request user\t", response.wsgi_request.user)
print("Is superuser\t", response.wsgi_request.user.is_superuser)
The Output
Redirect chain [('/admin/login/?next=/admin/management/establishment/', 302)]
Request user user
Is superuser True
Additional Information
Same result with a user having a password and an email
Tested on a new Django project
The Question
Do you know why I have this redirection and how I can avoid it?
Problem source
It seems that setting a user as superuser with is_superuser=True does not allow them to access the Django admin interface.
Only staffs can log in, so the is_staff=True attribute must be added to the user creation.
It's surprising that superusers are not considered staff by default.
Solution
Creating the user with the following line does not redirect to the login page:
user = User.objects.create(username='user', is_superuser=True, is_staff=True)
test.html:
authorize
views.py:
from django.contrib.auth.decorators import login_required
#login_required
def myview(req):
user = req.user
return render(req, 'test.html')
For ebay's oauth process, you have to provide users with a link to ebay's server, which asks the user if they want to give credentials to you. If they accept, ebay redirects the user to a given url with a querystring containing the access key.
The problem is, when I authorize my app with ebay, the user gets redirected to my login page (despite already being logged in). If I remove the #login_required decorator, req.user returns AnonymousUser instead. This is a problem since I don't know which user to assign the access token to.
What am I missing here?
Note that I am using ngrok to tunnel my server, and I have no problems
rendering myview other than the fact that the user is Anonymous.
The problem was that when I logged the user in initially, I was using the domain localhost:8000 instead of my ngrok instance.
Logging my user in using my ngrok address fixed the problem.
I have a Django app that uses the builtin login system.
I'm trying to write a unit test that verifies that the login url redirects to home if the user is already authenticated. Meaning, if an already authenticated user tries to visit the login url, they get redirected to home.
This is a built-in feature of Django's LoginView, and I have verified that it is indeed working. However, I'm not sure how to write a unit test for this.
Question: How do I verify that this redirect occurs via unit tests? LoginView returns a TemplateResponse, which doesn't have a url parameter.
What I have so far is this:
from django.test import TestCase
from django.urls import reverse
home = reverse('home')
login = reverse('login')
logout = reverse('logout')
signup = reverse('signup')
USER_CREDS = { some users credentials }
class TestLoginView(TestCase):
def test_login_redirect(self):
self.client.post(signup, USER_CREDS)
self.client.get(logout)
self.client.post(login, USER_CREDS)
response = self.client.get(login)
self.assertRedirects(response, home)
EDIT:
SimpleTestCase.assertRedirects does not work for TemplateResponse objects.
TemplateResponse objects do not contain a url parameter, which is required for SimpleTestCase.assertRedirect.
The method raises the following error: AttributeError: 'TemplateResponse' object has no attribute 'url'
This is not the same as the linked question, because the response object from a LoginView is a TemplateResponse, not an HttpResponse.
You can check that the login process redirects to the desired named URL with assertRedirects:
SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)
Asserts that the response returned a status_code redirect status,
redirected to expected_url (including any GET data), and that the
final page was received with target_status_code.
Then in your test:
self.assertRedirects(response, home)
Edit
I've just had a similar problem, few notes:
Instead of performing the login process, you can use TestCase.force_login that skips the authentication and verification steps.
class TestLoginView(TestCase):
def test_login_redirect(self):
self.client.force_login(user)
# logged user retrieves the login page
response = self.client.get(login)
self.assertRedirects(response, home)
Response should be a 302 redirect to home: <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/">
If you are not getting a redirect when doing response = self.client.get(login) that means that it is loading the login page, which is what you don't want, so you have to fix that error.
So the problem is not that TemplateResponse objects do not contain a url parameter, it is that your login page isn't redirecting a logged in user to the home page.
I'm using AngularJS as client fw, and django rest framework. I'm at the authentication part and was wondering if it is possible to POST us/pw and then login the user at the backend and then be able to access using the #login_required.
I'd like to avoid using $cookies in the client and then if I'm not logged in server responds with a 404 and then angular redirects the user to login page. When a user is logged in the user will have access too the server.
Is is even possible to be logged in at django on localhost:8000 and then access from localhost:82?
For trying I've logged in to admin-page(now the user is logged in) and then accessing some info from localhost:82 which is not working
angular.js:11442 GET http://localhost:8000/website/api/order/?format=json 404 (Not Found)
#api_view(['POST'])
def login(request):
if request.method == 'POST':
#print(request.data['password'])
username = request.data['username'];
password = request.data['password'];
user = auth.authenticate(username=username,password=password);
if user is not None:
if user.is_active:
auth.login(request,user);
return Response(200)
else:
return Response(404)
else:
return Response(404)
The validation works, when I type the real username and password I get 200 as a response, If I login with a admin account from the client shall I not be able to access the admin page if I type localhost/admin? Currently I'm not logged in when I try to access admin-page.
If you want to use SessionAuthentication you have to be on the same host. The server has no possibility to check whether you are the same user when you access the page from a different host.
If your angular.js app is running on a different host, you should authenticate via TokenAuthentication or some more sophisticated method like JSON WTA.
Maybe a stupid question here:
Is Requests(A python HTTP lib) support Django 1.4 ?
I use Requests follow the Official Quick Start like below:
requests.get('http://127.0.0.1:8000/getAllTracks', auth=('myUser', 'myPass'))
but i never get authentication right.(Of course i've checked the url, username, password again and again.)
The above url 'http://127.0.0.1:8000/getAllTracks' matches an url pattern of the url.py of a Django project, and that url pattern's callback is the 'getAllTracks' view of a Django app.
If i comment out the authentication code of the 'getAllTracks' view, then the above code works OK, but if i add those authentication code back for the view, then the above code never get authenticated right.
The authentication code of the view is actually very simple, exactly like below (The second line):
def getAllTracks(request):
if request.user.is_authenticated():
tracks = Tracks.objects.all()
if tracks:
# Do sth. here
Which means if i delete the above second line(with some indents adjustments of course), then the requests.get() operation do the right thing for me, but if not(keep the second line), then it never get it right.
Any help would be appreciated.
In Django authentication works in following way:
There is a SessionMiddleware and AuthenticationMiddleware. The process_request() of both these classes is called before any view is called.
SessionMiddleware uses cookies at a lower level. It checks for a cookie named sessionid and try to associate this cookie with a user.
AuthenticationMiddleware checks if this cookie is associated with an user then sets request.user as that corresponding user. If the cookie sessionid is not found or can't be associated with any user, then request.user is set to an instance of AnonymousUser().
Since Http is a stateless protocol, django maintains session for a particular user using these two middlewares and using cookies at a lower level.
Coming to the code, so that requests can work with django.
You must first call the view where you authenticate and login the user. The response from this view will contain sessionid in cookies.
You should use this cookie and send it in the next request so that django can authenticate this particular user and so that your request.user.is_authenticated() passes.
from django.contrib.auth import authenticate, login
def login_user(request):
user = authenticate(username=request.POST.get('username'), password=request.POST.get('password'))
if user:
login(request, user)
return HttpResponse("Logged In")
return HttpResponse("Not Logged In")
def getAllTracks(request):
if request.user.is_authenticated():
return HttpResponse("Authenticated user")
return HttpResponse("Non Authenticated user")
Making the requests:
import requests
resp = requests.post('http://127.0.0.1:8000/login/', {'username': 'akshar', 'password': 'abc'})
print resp.status_code
200 #output
print resp.content
'Logged In' #output
cookies = dict(sessionid=resp.cookies.get('sessionid'))
print cookies
{'sessionid': '1fe38ea7b22b4d4f8d1b391e1ea816c0'} #output
response_two = requests.get('http://127.0.0.1:8000/getAllTracks/', cookies=cookies)
Notice that we pass cookies using cookies keyword argument
print response_two.status_code
200 #output
print response_two.content
'Authenticated user' #output
So, our request.user.is_authenticated() worked properly.
response_three = requests.get('http://127.0.0.1:8000/hogwarts/getAllTracks/')
Notice we do not pass the cookies here.
print response_three.content
'Non Authenticated user' #output
I guess, auth keyword for Requests enables HTTP Basic authentication which is not what is used in Django. You should make a POST request to login url of your project with username and password provided in POST data, after that your Requests instance will receive a session cookie with saved authentication data and will be able to do successful requests to auth-protected views.
Might be easier for you to just set a cookie on initial authentication, pass that back to the client, and then for future requests expect the client to send back that token in the headers, like so:
r = requests.post('http://127.0.0.1:8000', auth=(UN, PW))
self.token = r.cookies['token']
self.headers = {'token': token}
and then in further calls you could, assuming you're in the same class, just do:
r = requests.post('http://127.0.0.1:8000/getAllTracks', headers=self.headers)