Dmi*_*nov 5 authentication django django-authentication django-rest-framework
我已使用TokenAuthentication启用了使用DRF的用户身份验证
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication'
),
'DEFAULT_MODEL_SERIALIZER_CLASS':
'rest_framework.serializers.ModelSerializer',
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
#'EXCEPTION_HANDLER': 'apps.core.exceptions.custom_exception_handler'
}
Run Code Online (Sandbox Code Playgroud)
我有以下型号:
class Device(CreationModificationMixin):
"""
Contains devices (WW controllers). A device may be associated with the Owner
"""
_STATUSES = (
('A', 'Active'), # when everything is okay
('I', 'Inactive'), # when we got nothing from SPA controllers for X minutes
('F', 'Failure'), # when controller says it has issues
)
_TYPES = (
('S', 'Spa'),
('P', 'Pool'),
)
udid = models.CharField(max_length=255, verbose_name="Unique ID / MAC Address", help_text="MAC Address of WiFi controller", unique=True, null=False, blank=False, db_index=True)
type = models.CharField(max_length=1, choices=_TYPES, null=False, blank=False)
title = models.CharField(max_length=255, null=False, blank=False, db_index=True)
status = models.CharField(max_length=1, default='A', choices=_STATUSES)
pinged = models.DateTimeField(null=True)
owner = models.ForeignKey(Owner, verbose_name="Owner", null=True, blank=True, db_index=True)
def __str__(self):
return self.udid
Run Code Online (Sandbox Code Playgroud)
这表示将向API端点发送离散请求的硬件设备,因此我需要对每个请求进行身份验证,理想情况下使用基于令牌的标识,如
POST /api/devices/login
{
udid: '...mac address...',
hash: '...sha256...hash string',
time: '2015-01-01 12:24:30'
}
Run Code Online (Sandbox Code Playgroud)
hash将在设备端计算为sha256(salt + udid + current_time),将在DRF端内计算相同的哈希值/ login以进行比较并生成将保存在REDIS中并返回响应的令牌.
所有将来的请求都将此标记作为标头传递,将在自定义Permission类中进行检查.
我的问题:
我应该把这个功能放在哪里?
正如@ daniel-van-flymen指出的那样,返回设备而不是用户可能不是一个好主意.所以我所做的是创建一个DeviceUser扩展django.contrib.auth.models.AnonymousUser并返回我的自定义身份验证的类(毕竟设备基本上是匿名用户).
from myapp.models import Device
from rest_framework import authentication
from django.contrib.auth.models import AnonymousUser
from rest_framework.exceptions import AuthenticationFailed
class DeviceUser(AnonymousUser):
def __init__(self, device):
self.device = device
@property
def is_authenticated(self):
return True
class DeviceAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
udid = request.META.get("HTTP_X_UDID", None)
if not udid:
return None
try:
device = Device.objects.get(udid=udid)
except Device.DoesNotExist:
raise AuthenticationFailed("Invalid UDID")
if not device.active:
raise AuthenticationFailed("Device is inactive or deleted")
request.device = device
return (DeviceUser(device), None)
Run Code Online (Sandbox Code Playgroud)
此代码存在myapp.authentication,您可以将以下内容添加到您的设置中:
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"myapp.authentication.DeviceAuthentication",
)
}
Run Code Online (Sandbox Code Playgroud)
原始规范中的几个注释:我已经在验证器中修改了包含设备的请求,因此您可以这样做request.device.is_authenticated; 但是,用户DeviceUser也是如此,您也可以这样做request.user.device.is_authenticated(只要您对device属性进行适当的检查).
您的原始规范也要求实现TokenAuthentication,并且可以将此身份验证类子类化为更直接地使用它; 为简单起见,我只是让设备在其请求中包含X-UDID标头.
另请注意,与令牌身份验证机制一样,您必须将此方法与HTTPS一起使用,否则UDID将以纯文本格式发送,允许某人模拟设备.
您可以继承 DRF 的 BaseAuthentication 类并重写 .authenticate(self, request) 方法。成功验证后,此函数应返回 (device, None)。这将在 request.user 属性中设置设备对象。您可以在设备模型类中实现 is_authenticated()。
class APICustomAuthentication(BaseAuthentication):
---
def authenticate(self, request):
----
return (device, None) # on successful authentication
Run Code Online (Sandbox Code Playgroud)
将 APICustomAuthentication 添加到设置中的“DEFAULT_AUTHENTICATION_CLASSES”。
更多详细信息请参见此处
| 归档时间: |
|
| 查看次数: |
965 次 |
| 最近记录: |