I've set up Tastypie within a Django project and the API is correctly serving resources. I am now trying to allow mobile users (applications) to sign up, sign in and sign out through said API.
class BaseResource(ModelResource):
class Meta:
allowed_methods = [ 'get' ]
authentication = BasicAuthentication()
class UserResource(BaseResource):
class Meta:
queryset = User.objects.all()
resource_name = 'users'
...
class ProfileResource(BaseResource):
class Meta:
queryset = Profile.objects.all()
resource_name = 'profiles'
...
So this serves my first purpose. Regarding the login, I don't think BasicAuthentication
is appropriated for requests from a mobile. From what I've read there seem to be several ways to do what I want:
What bothers me in the first link (see the answer) is that the mobile application has to send JSON containing the raw password:
{ 'username' : 'me', 'password' : 'l33t' }
Isn't it possible that someone/thing grab this JSON and thus have access to the password ? Wouldn't it be better to use ApiKeyAuthentication
?
I understand less and less the more I read about it. If the account has been created from the Web platform (django-userena
) then I can't use ApiKeyAuthentication
because the key should be created when a new User
is saved.
I can find several ways of doing what I want, and I can't find the right one... I do realize this question has been asked and answered many times, but I'm looking fo directions about implementing this in the best way regarding my needs.
I ended up doing the following:
# ──────────────────────────────────────────────────────────────────────────────
class BaseResource(ModelResource):
# ──────────────────────────────────────
def prepend_urls(self):
try:
additional_urls = self._meta.additional_urls
except AttributeError:
additional_urls = []
return [url(r'^'+u[0]+'$', self.wrap_view(u[1]), name=u[2]) for u in additional_urls]
# ──────────────────────────────────────
def update_in_place(self, request, original_bundle, new_data):
try:
allowed_fields = self._meta.allowed_fields
except AttributeError:
allowed_fields = None
if allowed_fields and set(new_data.keys()) - set(allowed_fields):
raise BadRequest('Only alterable field(s): {}'.format(', '.join(allowed_fields)))
return super(ProfileResource, self).update_in_place(request, original_bundle, new_data)
# ──────────────────────────────────────
class Meta:
abstract = True
allowed_methods = ['get',]
authentication = ApiKeyAuthentication()
authorization = DjangoAuthorization()
max_limit = 1000
# ──────────────────────────────────────────────────────────────────────────────
class UserResource(BaseResource):
...
# ──────────────────────────────────────
def signup(self, request, **kwargs):
...
# ──────────────────────────────────────
def signin(self, request, **kwargs):
self.method_check(request, allowed=['post'])
data = self.deserialize(
request,
request.body,
format=request.META.get('CONTENT_TYPE', 'application/json')
)
username = data.get('username', '')
password = data.get('password', '')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
# login(request, user)
try:
key = ApiKey.objects.get(user=user)
if not key.key:
key.save()
except ApiKey.DoesNotExist:
key = ApiKey.objects.create(user=user)
return self.create_response(request, {
'success': True,
'data': key.key,
})
else:
return self.create_response(request, {
'success': False,
'message': 'User is not active',
}, HttpForbidden)
else:
return self.create_response(request, {
'success': False,
'message': 'Wrong password',
}, HttpUnauthorized)
# ──────────────────────────────────────
class Meta(BaseResource.Meta):
allowed_methods = ['get', 'patch',]
queryset = User.objects.all()
resource_name = 'users'
excludes = [ 'first_name', 'last_name', 'password' ]
filtering = {
...
}
additional_urls = [
('signup/', 'signup', 'api-signup'),
('signin/', 'signin', 'api-signin'),
]
allowed_fields = ['email',]