Creating auth token for non user object django rest framework - python

I am looking to generate a django authtoken for a non user object. previously I had easily generated auth tokens for user objects like this
email = request.data.get('email')
user = User.objects.get(email=email)
Token.objects.create(user=user)
but if I am trying this for non user object it is not getting generated.
device_id = request.data.get('device_id')
tablet = Table.objects.get(device_id=device_id)
Token.objects.create(user=tablet)
Here Table is simple model holding various device_ids.
I just want to generate an auth token for each tablet like we do for each user.

If you are linking devices to users, and need a "per device" token where a user has >1 device (e.g. desktop, tablet, phone, etc) that are logged in separately and where the tokens can be revoked, then look at the Knox App:
Django Knox (https://github.com/James1345/django-rest-knox)
Otherwise, authentication tokens are normally used to log in a user. If you don't have a user then they aren't much use as far as the standard infrastructure is concerned.
If you want something custom, then you'll have to write your own solution, which might include:
A custom middleware if:
you want/need to set request.device=, like request.user
you want a custom user object (below)
Decide if you want a "fake" user like DeviceUser
Implement the User interface (see AnonymousUser's example)
Has is_authenticated=True
Has permissions (?)
Has is_device_user=True so you can distinguish
Be really careful not to rely on request.user to have a user_id
Possibly a new Permission class (e.g. a new IsAuthenticated)
The main problem I see is with things that expect a non-anonymous User object (in request) to be a real user with a pk. If you are careful then this might not be too big an issue, but you'll need to start implementing to be sure how it affects you.

Related

django authentication model - login with emailed link?

Is there a way to set up the django authentication model where, instead of a password, users put in their email address, and then are emailed a link that they click on to login with? If so, are there any tutorials on how to set this up?
Yes, there is.
You'll either need to hope there is already a module out for this, otherwise you will have to write your own way of authenticating.
I'll give a rough estimate of how it's gonna work.
First, you will need to create a class inheriting from AbstractBaseUser
Set the username field to email, still include password fields. They are required.
Then, you will need to create a manager for that custom base user.
the user manager must have two methods: create_user() and create_superuser()
Then, in a view, have user enter their email address, and then generate a token with Django's default_token_generator, and send that token via e-mail to the user.
Create a view which accepts the token, and logs the user in.
I highly advise you to take the docs as your guide. This might get relatively complicated.
More info on the Django Docs
Side note: This will not be as secure as email and password validation. If a user's email gets hacked, the hackers will instantly know not only which site they can target, but also get a free pass to access.
Alternatively; check out Django AllAuth, they provide lots of ways to authenticate, including with Gmail or Facebook. There are some great tutorials online, but you'll have to do some googling. ;)

Django complementary external source authentication

I'm trying to build a Django website that will be maintained and used by university students mainly. I need to restrict access to a few pages for certain approved students, but it would be very unmaintainable if I needed to create a new Django user for every student that wants to log in. Luckily, the university provides an API to check whether a username/password combination is correct. So I had the idea to create an authentication model complementary to Django's model, where users' university account can get approved by an admin, after which it is a valid login to view certain pages.
So essentially, some users may use a Django account (if they're in charge for the content of the website), and other users may just log in to view some pages with their uni account. For the uni account, the minimum amount of info should be stored (in other words, only the username is really required to approve certain users).
I can't seem to figure out how to build such a system in Django. I cannot use the standard User object because it stores data that is completely redundant, and I cannot substitute the user model because that would only make things incredibly complex. It seems reasonable to forget the User model altogether, but Authenticate needs to return a valid user. This makes me wonder, can I create regular Django users with as little information filled in as possible (dummy data except for the username), and then authenticate them with the API? Probably, but that hardly seems like a good idea.
To authenticate users using the university API, all you need to do is to write an authentication backend. You can then create a local user for these uni users the first time they login, since there is only two required fields: username and password. You can use set_unusable_password() so check_password() for this user will never return True.
The Django admin system is tightly coupled to the Django User object
described at the beginning of this document. For now, the best way to
deal with this is to create a Django User object for each user that
exists for your backend (e.g., in your LDAP directory, your external
SQL database, etc.) You can either write a script to do this in
advance, or your authenticate method can do it the first time a user
logs in.

Django password and authentication for non standard users

I have been asked to introduce an unusual case and I'm wondering how others would go about it.
I have users in my Django application. The model is a standard user model, authentication. etc. Each one of of these site users can add their own contacts to the system. However my new requirement is to allow their contacts to set a password (if they want to to) so that they can login to their status page (belonging to that user).
So my question is how would you do this? I already have the contact table (which belongs to one user), I'm thinking of adding in a password (optional) field, but then I'm unsure how to handle the authentication for this as they are not my users but members of my users (if that make sense).
One way would be to create another user model for contacts inheriting from AbstractBaseUser. And then creating custom auth backend that would look in both models to login user. Finaly you would have to distinguish between standard user and contact user before every action.
That is if contact user and standard user differ significantly in your application.
Or you could just create custom user in your application, that would contain is_contact attribute. This would be used for both types of users. You would set that as AUTH_USER_MODEL in settings and check before every action for the is_contact attribute to determine the outcome. You could return 403 for the contact user if he tries to access what he's not suppose to.
Or if you use permissions in your application, you could set the contact user's persmissions only to view statuses of the users that added him as a contact and nothing else.

Connecting methods Python

I am currently using Oauth to allow a user to sign in through Foursquare, I then create a new session for this user. If the user is new to the system they are asked to sign in through Hunch, this can then generate a user profile based on information from both systems. I have them both signing in to each application separately, but how can I associate the user logged in with Foursquare to the one in Hunch.
My idea for it was to somehow create a reference to the session id in the user model, or use the session ID as a parameter for the hunch sign in but I'm not sure if this would be the best idea. Is there any other way in which I can create the association?
The easiest way to do this would be something like the following:
Send the user to foursquare to sign in
When the user returns, create a record in the datastore for them.
Send the user to Hunch to sign in, but include the ID of the record you created in step 2 in the continue URL.
When the user returns, use the ID embedded in the URL to add the user's Hunch info to their user record.
You can create a parent association so that SiteUser is the parent of FoursquareAuth and HunchAuth.
When the user first logs in with Foursquare you create the SiteUser model and then create the FoursquareAuth model with parent=just_created_user. Then when you send the user off to authenticate through hunch you include the user's id, or a session id in the callback parameter. When the callback happens you get the user's key and create HunchAuth with parent=previously_created_user.
The SiteUser model contains the combined information from both sources (name, location, last checkin, etc.). The *Auth models just contain whatever guaranteed unique identifiers are supplied by each provider (user_id, access_token, etc.).
This way, if you have the user object you can find either the Foursquare or the Hunch authentication data (using an ancestor filter), and you can find a user by loading any *Auth model and fetching its parent().
(note: I call the model SiteUser to not confuse it with the User object available in App Engine)

How to change default django User model to fit my needs?

The default Django's User model has some fields, and validation rules, that I don't really need. I want to make registration as simple as possible, i.e. require either email or username, or phone number - all those being unique, hence good as user identifiers.
I also don't like default character set for user name that is validated in Django user model. I'd like to allow any character there - why not?
I used user-profile django application before to add a profile to user - but this time I'd rather make the class mimimal. But I still want to use the User class, as it gives me an easy way to have parts of site restricted only for users logged in.
How do I do it?
Rather than modify the User class directly or do subclassing, you can also just repurpose the existing fields.
For one site I used the "first_name" field as the "publicly displayed name" of a user and stuff a slugified version of that into the "username" field (for use in URLs). I wrote a custom auth backend to allow people to log in using their "public name" or their email address, and I enforce the uniqueness of both of those at registration time. This plays nicely with other reusable apps and doesn't introduce extra tables or queries.
For another site I didn't want usernames at all, just unique emails. In order to satisfy Django's need for a unique username, I just hashed the email address and used that as the username (you have to base64-encode the hash to squeeze it under 30 characters). Custom auth backend to allow login with email.
If backwards-compatibility weren't an issue, there are a lot of improvements I'd love to see made to django.contrib.auth and the User model to make them more flexible. But there's quite a lot you can do inside the current constraints with a little creativity.
I misread the question. Hope this post is helpful to anyone else.
#in models.py
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.ForeignKey(User)
#other fields here
def __str__(self):
return "%s's profile" % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
#in settings.py
AUTH_PROFILE_MODULE = 'YOURAPP.UserProfile'
This will create a userprofile each time a user is saved if it is created.
You can then use
user.get_profile().whatever
Here is some more info from the docs
http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
The Django User model is structured very sensibly. You really don't want to allow arbitrary characters in a username, for instance, and there are ways to achieve email address login, without hacking changes to the base model.
To simply store additional information around a user account, Django supports the notion of user profiles. While you don't need to rely on the built in support to handle this, it is a convention that is commonly followed and it will allow you to play nice with the reusable Django apps that are floating around in the ether. For more information, see here.
If you want to actually modify the core User model but also "play nice" with reusable apps that rely on it, you're opening a bit of a Pandora's Box. Developers make base assumptions about how the core library is structured, so any changes may cause unexpected breakage. Nonetheless, you can monkeypatch changes to the base model, or branch a copy of Django locally. I would discourage the latter, and only recommend the former if you know what you're doing.
You face a bit of a dilemma which really has two solutions if you're committed to avoiding the profile-based customization already pointed out.
Change the User model itself, per Daniel's suggestions
Write a CustomUser class, subclassing User or copying its functionality.
The latter suggestion means that you would have to implement some things that User does automatically manually, but I wonder whether that's as bad as it sounds, especially if you're at the beginning of your project. All you'd have to do is rewrite a middle-ware class and some decorators.
Of course, I don't think this buys you anything that 1 won't get you, except that your project shouldn't break if you svn update your django. It may avoid some of the compatibility problems with other apps, but my guess is most problems will exist either way.
There are anumber of ways to do this, but here's what I'd do: I'd allow a user to enter an email, username (which must contain at least one letter and no # symbols) or mobile number. Then, when I validate it:
Check for the presence of #. If so, set it as the user's email, hash it appropriately and set it as their username as well.
Check to see if it's only numbers, dashes and +. Then, strip the appropriate characters and store it as both mobile number and username (if you're storing the mobile number in another model for SMS purposes or something).
If it's not either, just set it as username.
I'd also validate the user/phone/email field similarly on login and look in the appropriate place so that if, say, a user signs up with their mobile number and then changes their username (for some other purpose), they can still sign in with their mobile number.

Categories