[英]Django Rest Framework custom authentication
Django rest framework: Custom Authentication Django rest 框架:自定义身份验证
I want to use custom authentication in my Django app but cannot find how to apply this.我想在我的 Django 应用程序中使用自定义身份验证,但找不到如何应用它。 The example given in the documentation is clear to me but they did not mention where to create this new class and how to use this.文档中给出的示例对我来说很清楚,但他们没有提到在哪里创建这个新类以及如何使用它。
How to implement a custom authentication scheme in DRF?如何在 DRF 中实现自定义身份验证方案?
To implement a custom authentication scheme, we need to subclass the DRF's BaseAuthentication
class and override the .authenticate(self, request)
method.要实现自定义身份验证方案,我们需要BaseAuthentication
DRF 的BaseAuthentication
类并覆盖.authenticate(self, request)
方法。
The method should return a two-tuple of (user, auth)
if authentication succeeds, or None
otherwise.如果身份验证成功,该方法应返回(user, auth)
的二元组,否则返回None
。 In some circumstances, we may raise an AuthenticationFailed
exception from the .authenticate()
method.在某些情况下,我们可能会从.authenticate()
方法中引发AuthenticationFailed
异常。
Example (from DRF docs ):示例(来自DRF 文档):
Lets say we want to authenticate any incoming request as the user given by the username
in a custom request header named 'X_USERNAME'
.假设我们希望将任何传入请求作为名为'X_USERNAME'
的自定义请求标头中的username
指定的用户进行身份验证。
Step-1: Create the Custom authentication class步骤 1:创建自定义身份验证类
To do that, we will create an authentication.py
file in my_app
.为此,我们将在my_app
创建一个authentication.py
文件。
# my_app/authentication.py
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('X_USERNAME') # get the username request header
if not username: # no username passed in request headers
return None # authentication did not succeed
try:
user = User.objects.get(username=username) # get the user
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user') # raise exception if user does not exist
return (user, None) # authentication successful
Step-2: Specify the custom authentication class步骤 2:指定自定义身份验证类
After creating the custom authentication class, we need to define this authentication class in our DRF settings.创建自定义身份验证类后,我们需要在我们的 DRF 设置中定义此身份验证类。 Doing this, all the requests will be authenticated based on this authentication scheme.这样做,所有请求都将根据此身份验证方案进行身份验证。
'DEFAULT_AUTHENTICATION_CLASSES': (
'my_app.authentication.ExampleAuthentication', # custom authentication class
...
),
Note: If you want to use this custom authentication class on per-view basis or per-viewset basis and not on global level, you can define this authentication class explicitly in your views.注意:如果您想基于每个视图或每个视图集而不是全局级别使用此自定义身份验证类,则可以在视图中明确定义此身份验证类。
class MyView(APIView):
authentication_classes = (ExampleAuthentication,) # specify this authentication class in your view
...
Below is a simple example that can be used to achieve a custom authentication.下面是一个可用于实现自定义身份验证的简单示例。 To access the endpoint you have to pass the username&password on the POST data.要访问端点,您必须在 POST 数据上传递用户名和密码。
urls.py网址.py
urlpatterns = [
url(r'^stuff/', views.MyView.as_view()),
...
]
views.py视图.py
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework import exceptions
from rest_framework import authentication
from django.contrib.auth import authenticate, get_user_model
from rest_framework.authentication import SessionAuthentication
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
# Get the username and password
username = request.data.get('username', None)
password = request.data.get('password', None)
if not username or not password:
raise exceptions.AuthenticationFailed(_('No credentials provided.'))
credentials = {
get_user_model().USERNAME_FIELD: username,
'password': password
}
user = authenticate(**credentials)
if user is None:
raise exceptions.AuthenticationFailed(_('Invalid username/password.'))
if not user.is_active:
raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))
return (user, None) # authentication successful
class MyView(APIView):
authentication_classes = (SessionAuthentication, ExampleAuthentication,)
permission_classes = (IsAuthenticated,)
def post(self, request, format=None):
content = {
'user': unicode(request.user),
'auth': unicode(request.auth), # None
}
return Response(content)
Curl卷曲
curl -v -X POST http://localhost:8000/stuff/ -d 'username=my_username&password=my_password'
I used the following way我使用了以下方式
from rest_framework_jwt.settings import api_settings
from rest_framework import status, generics
class UserLogin(generics.CreateAPIView):
def post(self, request, *args, **kwargs):
email = request.data['email']
if email is None:
return Response({'error': 'Email not informed'}, status=status.HTTP_403_FORBIDDEN)
try:
user = User.objects.get(email=email)
if not user.check_password(request.data['password']):
return Response({'error': 'Email ou senha incorreto'}, status=status.HTTP_400_BAD_REQUEST)
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({"token": token, "user":UserSessionSerializerAuth(user,
context={'request': request}).data}, status=status.HTTP_200_OK)
except User.DoesNotExist:
return Response({'error': 'User not found'}, status=status.HTTP_403_FORBIDDEN)
In the folder that holds your api files, create another file to hold your custom authentication class, such as authentication.py
.在保存 api 文件的文件夹中,创建另一个文件来保存您的自定义身份验证类,例如authentication.py
。 Then in your settings, under DEFAULT_AUTHENTICATION_CLASSES , point to your custom authentication class.然后在您的设置中,在DEFAULT_AUTHENTICATION_CLASSES下,指向您的自定义身份验证类。
I faced similar situation where I had to implement a custom authentication class.我遇到了类似的情况,我必须实现自定义身份验证类。 Request coming to the rest endpoint were using basic auth
but the username weren't a django user.到达其余端点的请求正在使用basic auth
但用户名不是 django 用户。 Requests were authnticated against username and password configured in settings.py
.要求被authnticated对用户名和密码在配置settings.py
。 Here's my implementation:这是我的实现:
- Created custom authentication class - 创建自定义身份验证类
# myapp/api/auth.py
"""Custom authentication module"""
import base64
import binascii
from django.conf import settings
from django.utils.six import text_type
from django.utils.translation import ugettext_lazy as _
from rest_framework.authentication import BaseAuthentication
from rest_framework import HTTP_HEADER_ENCODING, exceptions
class CustomAuthentication(BaseAuthentication):
"""
Custom authentication class.
It will authenticate any incoming request
as the user given by the username in a
custom request header.
"""
def authenticate(self, request):
"""
Returns a `User` if a correct username and password have been supplied
using HTTP Basic authentication. Otherwise returns `None`.
"""
# Gets authorization from request header
# and checks different possibility of
# invalid header.
# ======================================
auth = self.get_authorization_header(request).split()
if not auth or auth[0].lower() != b"basic":
raise exceptions.AuthenticationFailed(_("Invalid header!"))
if len(auth) == 1:
msg = _("Invalid basic header. No credentials provided.")
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _(
"Invalid basic header. Credentials string should not contain spaces."
)
raise exceptions.AuthenticationFailed(msg)
try:
auth_parts = (
base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(":")
)
except (TypeError, UnicodeDecodeError, binascii.Error):
msg = _("Invalid basic header. Credentials not correctly base64 encoded.")
raise exceptions.AuthenticationFailed(msg)
# parses username and password.
userid, password = auth_parts[0], auth_parts[2]
if userid != settings.FERRATUM_CALLBACK_USERNAME:
msg = _("Invalid basic header. Username is incorrect!")
raise exceptions.AuthenticationFailed(msg)
if password != settings.FERRATUM_CALLBACK_PASSWORD:
msg = _("Invalid basic header. Password is incorrect!")
raise exceptions.AuthenticationFailed(msg)
# An user object is expected to be returned
# in case of successful authentication. Therefore
# a user object is returned with the give username
# in the header. This user doesn't exists in the
# django user User model.
# ===============================================
user = {
"username": userid,
"password": "",
"email": "",
"first_name": "",
"last_name": "",
"company": "",
}
return (user, None)
@staticmethod
def get_authorization_header(request):
"""
Return request's 'Authorization:' header, as a bytestring.
Hide some test client ickyness where the header can be unicode.
"""
auth = request.META.get("HTTP_AUTHORIZATION", b"")
if isinstance(auth, text_type):
# Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING)
return auth
- Added it in DEFAULT_AUTHENTICATION_CLASS - 在 DEFAULT_AUTHENTICATION_CLASS 中添加它
# myapp/settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework.authentication.SessionAuthentication",
"mozilla_django_oidc.contrib.drf.OIDCAuthentication",
"rest_framework.authentication.BasicAuthentication",
"users.auth.SaveriumTokenAuthentication",
"api.auth.CustomAuthentication"
),
'DEFAULT_RENDERER_CLASSES': DEFAULT_RENDERER_CLASSES
}
- Used the custom authentication in view - 在视图中使用自定义身份验证
# myapp/api/view/api_view.py
from api.auth import CustomAuthentication
class UpdateStatus(APIView):
"""
It updates application status
"""
# Custom authentication scheme.
authentication_classes = [CustomAuthentication]
def post(self, *args, **kwargs):
"""
Callback comes as a POST request
with data in JSON format.
"""
data = self.request.data
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.