Add per-user token-based API authentication.

This commit is contained in:
Christopher Charbonneau Wells 2017-12-05 10:46:59 -05:00
parent e9a80504e2
commit a9c0757b4d
5 changed files with 41 additions and 2 deletions

View File

@ -7,6 +7,8 @@ from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.timezone import timedelta from django.utils.timezone import timedelta
from rest_framework.authtoken.models import Token
class Settings(models.Model): class Settings(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
@ -30,6 +32,16 @@ class Settings(models.Model):
def __str__(self): def __str__(self):
return '{}\'s Settings'.format(self.user) return '{}\'s Settings'.format(self.user)
def api_key(self, reset=False):
"""
Get or create an API key for the associated user.
:param reset: If True, delete the existing key and create a new one.
:return: The user's API key.
"""
if reset:
Token.objects.get(user=self.user).delete()
return Token.objects.get_or_create(user=self.user)[0]
@property @property
def dashboard_refresh_rate_milliseconds(self): def dashboard_refresh_rate_milliseconds(self):
""" """

View File

@ -35,6 +35,7 @@ INSTALLED_APPS = [
'django_filters', 'django_filters',
'rest_framework', 'rest_framework',
'rest_framework.authtoken',
'widget_tweaks', 'widget_tweaks',
'easy_thumbnails', 'easy_thumbnails',
@ -144,6 +145,10 @@ WHITENOISE_ROOT = os.path.join(BASE_DIR, 'static', 'root')
# http://www.django-rest-framework.org/# # http://www.django-rest-framework.org/#
REST_FRAMEWORK = { REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_FILTER_BACKENDS': [ 'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend', 'django_filters.rest_framework.DjangoFilterBackend',
], ],

View File

@ -50,6 +50,16 @@
{% endwith %} {% endwith %}
</div> </div>
</fieldset> </fieldset>
<fieldset>
<legend>API</legend>
<div class="form-group row">
<label for="id_email" class="col-sm-2 col-form-label">Key</label>
<div class="col-sm-10">
<samp>{{ user.settings.api_key }}</samp>
<a class="btn btn-xs btn-danger" href="{% url 'babybuddy:user-reset-api-key' %}">Regenerate</a>
</div>
</div>
</fieldset>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>
</div> </div>

View File

@ -17,10 +17,13 @@ app_patterns = [
url(r'^$', views.RootRouter.as_view(), name='root-router'), url(r'^$', views.RootRouter.as_view(), name='root-router'),
url(r'^welcome/$', views.Welcome.as_view(), name='welcome'), url(r'^welcome/$', views.Welcome.as_view(), name='welcome'),
url(r'^user/settings/$', views.UserSettings.as_view(),
name='user-settings'),
url(r'^user/password/$', views.UserPassword.as_view(), url(r'^user/password/$', views.UserPassword.as_view(),
name='user-password'), name='user-password'),
url(r'^user/reset-api-key/$', views.UserResetAPIKey.as_view(),
name='user-reset-api-key'),
url(r'^user/settings/$', views.UserSettings.as_view(),
name='user-settings'),
] ]
urlpatterns = [ urlpatterns = [

View File

@ -53,6 +53,15 @@ class UserPassword(LoginRequiredMixin, View):
return render(request, self.template_name, {'form': form}) return render(request, self.template_name, {'form': form})
class UserResetAPIKey(LoginRequiredMixin, View):
"""
Resets the API key of the logged in user.
"""
def get(self, request):
request.user.settings.api_key(reset=True)
return redirect('babybuddy:user-settings')
class UserSettings(LoginRequiredMixin, View): class UserSettings(LoginRequiredMixin, View):
""" """
Handles both the User and Settings models. Handles both the User and Settings models.