mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-23 22:49:50 +03:00
Merge b78872b7db
into e8f542aac8
This commit is contained in:
commit
104dde49c5
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The [permission] and [throttling] policies can then use those credentials to determine if the request should be permitted.
|
Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The [permission] and [throttling] policies can then use those credentials to determine if the request should be permitted.
|
||||||
|
|
||||||
REST framework provides a number of authentication policies out of the box, and also allows you to implement custom policies.
|
REST framework provides a number of authentication schemes out of the box, and also allows you to implement custom schemes.
|
||||||
|
|
||||||
Authentication will run the first time either the `request.user` or `request.auth` properties are accessed, and determines how those properties are initialized.
|
Authentication will run the first time either the `request.user` or `request.auth` properties are accessed, and determines how those properties are initialized.
|
||||||
|
|
||||||
|
@ -16,17 +16,23 @@ The `request.user` property will typically be set to an instance of the `contrib
|
||||||
|
|
||||||
The `request.auth` property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
|
The `request.auth` property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Note:** Don't forget that **authentication by itself won't allow or disallow an incoming request**, it simply identifies the credentials that the request was made with. For information on how to setup the permission polices for your API please see the [permissions documentation][permission].
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## How authentication is determined
|
## How authentication is determined
|
||||||
|
|
||||||
The authentication policy is always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set `request.user` and `request.auth` using the return value of the first class that successfully authenticates.
|
The authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set `request.user` and `request.auth` using the return value of the first class that successfully authenticates.
|
||||||
|
|
||||||
If no class authenticates, `request.user` will be set to an instance of `django.contrib.auth.models.AnonymousUser`, and `request.auth` will be set to `None`.
|
If no class authenticates, `request.user` will be set to an instance of `django.contrib.auth.models.AnonymousUser`, and `request.auth` will be set to `None`.
|
||||||
|
|
||||||
The value of `request.user` and `request.auth` for unauthenticated requests can be modified using the `UNAUTHENTICATED_USER` and `UNAUTHENTICATED_TOKEN` settings.
|
The value of `request.user` and `request.auth` for unauthenticated requests can be modified using the `UNAUTHENTICATED_USER` and `UNAUTHENTICATED_TOKEN` settings.
|
||||||
|
|
||||||
## Setting the authentication policy
|
## Setting the authentication scheme
|
||||||
|
|
||||||
The default authentication policy may be set globally, using the `DEFAULT_AUTHENTICATION` setting. For example.
|
The default authentication schemes may be set globally, using the `DEFAULT_AUTHENTICATION` setting. For example.
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_AUTHENTICATION': (
|
'DEFAULT_AUTHENTICATION': (
|
||||||
|
@ -35,7 +41,7 @@ The default authentication policy may be set globally, using the `DEFAULT_AUTHEN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
You can also set the authentication policy on a per-view basis, using the `APIView` class based views.
|
You can also set the authentication scheme on a per-view basis, using the `APIView` class based views.
|
||||||
|
|
||||||
class ExampleView(APIView):
|
class ExampleView(APIView):
|
||||||
authentication_classes = (SessionAuthentication, UserBasicAuthentication)
|
authentication_classes = (SessionAuthentication, UserBasicAuthentication)
|
||||||
|
@ -60,24 +66,43 @@ Or, if you're using the `@api_view` decorator with function based views.
|
||||||
}
|
}
|
||||||
return Response(content)
|
return Response(content)
|
||||||
|
|
||||||
|
## Unauthorized and Forbidden responses
|
||||||
|
|
||||||
|
When an unauthenticated request is denied permission there are two different error codes that may be appropriate.
|
||||||
|
|
||||||
|
* [HTTP 401 Unauthorized][http401]
|
||||||
|
* [HTTP 403 Permission Denied][http403]
|
||||||
|
|
||||||
|
The kind of response that will be used depends on the type of authentication scheme in use, and the ordering of the authentication classes.
|
||||||
|
|
||||||
|
Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. **The first authentication class set on the view is given priority when determining the type of response**.
|
||||||
|
|
||||||
|
Note that when a *successfully authenticated* request is denied permission, a `403 Permission Denied` response will always be used, regardless of the authentication scheme.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# API Reference
|
# API Reference
|
||||||
|
|
||||||
## BasicAuthentication
|
## BasicAuthentication
|
||||||
|
|
||||||
This policy uses [HTTP Basic Authentication][basicauth], signed against a user's username and password. Basic authentication is generally only appropriate for testing.
|
This authentication scheme uses [HTTP Basic Authentication][basicauth], signed against a user's username and password. Basic authentication is generally only appropriate for testing.
|
||||||
|
|
||||||
If successfully authenticated, `BasicAuthentication` provides the following credentials.
|
If successfully authenticated, `BasicAuthentication` provides the following credentials.
|
||||||
|
|
||||||
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
||||||
* `request.auth` will be `None`.
|
* `request.auth` will be `None`.
|
||||||
|
|
||||||
|
Unauthenticated responses that are denied permission will result in an `HTTP 401 Unauthorized` response with an appropriate WWW-Authenticate header. For example:
|
||||||
|
|
||||||
|
WWW-Authenticate: Basic realm="api"
|
||||||
|
|
||||||
**Note:** If you use `BasicAuthentication` in production you must ensure that your API is only available over `https` only. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
|
**Note:** If you use `BasicAuthentication` in production you must ensure that your API is only available over `https` only. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.
|
||||||
|
|
||||||
## TokenAuthentication
|
## TokenAuthentication
|
||||||
|
|
||||||
This policy uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
|
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
|
||||||
|
|
||||||
To use the `TokenAuthentication` policy, include `rest_framework.authtoken` in your `INSTALLED_APPS` setting.
|
To use the `TokenAuthentication` scheme, include `rest_framework.authtoken` in your `INSTALLED_APPS` setting.
|
||||||
|
|
||||||
You'll also need to create tokens for your users.
|
You'll also need to create tokens for your users.
|
||||||
|
|
||||||
|
@ -95,31 +120,56 @@ If successfully authenticated, `TokenAuthentication` provides the following cred
|
||||||
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
||||||
* `request.auth` will be a `rest_framework.tokenauth.models.BasicToken` instance.
|
* `request.auth` will be a `rest_framework.tokenauth.models.BasicToken` instance.
|
||||||
|
|
||||||
|
Unauthenticated responses that are denied permission will result in an `HTTP 401 Unauthorized` response with an appropriate WWW-Authenticate header. For example:
|
||||||
|
|
||||||
|
WWW-Authenticate: Token
|
||||||
|
|
||||||
**Note:** If you use `TokenAuthentication` in production you must ensure that your API is only available over `https` only.
|
**Note:** If you use `TokenAuthentication` in production you must ensure that your API is only available over `https` only.
|
||||||
|
|
||||||
## OAuthAuthentication
|
## OAuth2Authentication
|
||||||
|
|
||||||
This policy uses the [OAuth 2.0][oauth] protocol to authenticate requests. OAuth is appropriate for server-server setups, such as when you want to allow a third-party service to access your API on a user's behalf.
|
This authentication scheme uses the [OAuth 2.0][oauth] protocol to authenticate requests. OAuth is appropriate for server-server setups, such as when you want to allow a third-party service to access your API on a user's behalf.
|
||||||
|
|
||||||
If successfully authenticated, `OAuthAuthentication` provides the following credentials.
|
If successfully authenticated, `OAuth2Authentication` provides the following credentials.
|
||||||
|
|
||||||
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
||||||
* `request.auth` will be a `rest_framework.models.OAuthToken` instance.
|
* `request.auth` will be a `rest_framework.models.OAuthToken` instance.
|
||||||
|
|
||||||
|
**TODO**: Note type of response (401 vs 403)
|
||||||
|
|
||||||
|
**TODO**: Implement OAuth2Authentication, using django-oauth2-provider.
|
||||||
|
|
||||||
## SessionAuthentication
|
## SessionAuthentication
|
||||||
|
|
||||||
This policy uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website.
|
This authentication scheme uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website.
|
||||||
|
|
||||||
If successfully authenticated, `SessionAuthentication` provides the following credentials.
|
If successfully authenticated, `SessionAuthentication` provides the following credentials.
|
||||||
|
|
||||||
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
* `request.user` will be a `django.contrib.auth.models.User` instance.
|
||||||
* `request.auth` will be `None`.
|
* `request.auth` will be `None`.
|
||||||
|
|
||||||
|
Unauthenticated responses that are denied permission will result in an `HTTP 403 Forbidden` response.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# Custom authentication
|
# Custom authentication
|
||||||
|
|
||||||
To implement a custom authentication policy, subclass `BaseAuthentication` and override the `.authenticate(self, request)` method. The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise.
|
To implement a custom authentication scheme, subclass `BaseAuthentication` and override the `.authenticate(self, request)` method. The method should return a two-tuple of `(user, auth)` if authentication succeeds, or `None` otherwise.
|
||||||
|
|
||||||
|
In some circumstances instead of returning `None`, you may want to raise an `AuthenticationFailed` exception from the `.authenticate()` method.
|
||||||
|
|
||||||
|
Typically the approach you should take is:
|
||||||
|
|
||||||
|
* If authentication is not attempted, return `None`. Any other authentication schemes also in use will still be checked.
|
||||||
|
* If authentication is attempted but fails, raise a `AuthenticationFailed` exception. An error response will be returned immediately, without checking any other authentication schemes.
|
||||||
|
|
||||||
|
You *may* also override the `.authentication_header(self, request)` method. If implemented, it should return a string that will be used as the value of the `WWW-Authenticate` header in a `HTTP 401 Unauthorized` response.
|
||||||
|
|
||||||
|
If the `.authentication_header()` method is not overridden, the authentication scheme will return `HTTP 403 Forbidden` responses when an unauthenticated request is denied access.
|
||||||
|
|
||||||
[cite]: http://jacobian.org/writing/rest-worst-practices/
|
[cite]: http://jacobian.org/writing/rest-worst-practices/
|
||||||
|
[http401]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2
|
||||||
|
[http403]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4
|
||||||
[basicauth]: http://tools.ietf.org/html/rfc2617
|
[basicauth]: http://tools.ietf.org/html/rfc2617
|
||||||
[oauth]: http://oauth.net/2/
|
[oauth]: http://oauth.net/2/
|
||||||
[permission]: permissions.md
|
[permission]: permissions.md
|
||||||
|
|
|
@ -53,11 +53,27 @@ Raised if the request contains malformed data when accessing `request.DATA` or `
|
||||||
|
|
||||||
By default this exception results in a response with the HTTP status code "400 Bad Request".
|
By default this exception results in a response with the HTTP status code "400 Bad Request".
|
||||||
|
|
||||||
|
## AuthenticationFailed
|
||||||
|
|
||||||
|
**Signature:** `AuthenticationFailed(detail=None)`
|
||||||
|
|
||||||
|
Raised when an incoming request includes incorrect authentication.
|
||||||
|
|
||||||
|
By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the [authentication documentation][authentication] for more details.
|
||||||
|
|
||||||
|
## NotAuthenticated
|
||||||
|
|
||||||
|
**Signature:** `NotAuthenticated(detail=None)`
|
||||||
|
|
||||||
|
Raised when an unauthenticated request fails the permission checks.
|
||||||
|
|
||||||
|
By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the [authentication documentation][authentication] for more details.
|
||||||
|
|
||||||
## PermissionDenied
|
## PermissionDenied
|
||||||
|
|
||||||
**Signature:** `PermissionDenied(detail=None)`
|
**Signature:** `PermissionDenied(detail=None)`
|
||||||
|
|
||||||
Raised when an incoming request fails the permission checks.
|
Raised when an authenticated request fails the permission checks.
|
||||||
|
|
||||||
By default this exception results in a response with the HTTP status code "403 Forbidden".
|
By default this exception results in a response with the HTTP status code "403 Forbidden".
|
||||||
|
|
||||||
|
@ -86,3 +102,4 @@ Raised when an incoming request fails the throttling checks.
|
||||||
By default this exception results in a response with the HTTP status code "429 Too Many Requests".
|
By default this exception results in a response with the HTTP status code "429 Too Many Requests".
|
||||||
|
|
||||||
[cite]: http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html
|
[cite]: http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html
|
||||||
|
[authentication]: authentication.md
|
||||||
|
|
|
@ -21,6 +21,14 @@ class BaseAuthentication(object):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(".authenticate() must be overridden.")
|
raise NotImplementedError(".authenticate() must be overridden.")
|
||||||
|
|
||||||
|
def authenticate_header(self, request):
|
||||||
|
"""
|
||||||
|
Return a string to be used as the value of the `WWW-Authenticate`
|
||||||
|
header in a `401 Unauthenticated` response, or `None` if the
|
||||||
|
authentication scheme should return `403 Permission Denied` responses.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BasicAuthentication(BaseAuthentication):
|
class BasicAuthentication(BaseAuthentication):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -23,6 +23,22 @@ class ParseError(APIException):
|
||||||
self.detail = detail or self.default_detail
|
self.detail = detail or self.default_detail
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticationFailed(APIException):
|
||||||
|
status_code = status.HTTP_401_UNAUTHORIZED
|
||||||
|
default_detail = 'Incorrect authentication credentials.'
|
||||||
|
|
||||||
|
def __init__(self, detail=None):
|
||||||
|
self.detail = detail or self.default_detail
|
||||||
|
|
||||||
|
|
||||||
|
class NotAuthenticated(APIException):
|
||||||
|
status_code = status.HTTP_401_UNAUTHORIZED
|
||||||
|
default_detail = 'Authentication credentials were not provided.'
|
||||||
|
|
||||||
|
def __init__(self, detail=None):
|
||||||
|
self.detail = detail or self.default_detail
|
||||||
|
|
||||||
|
|
||||||
class PermissionDenied(APIException):
|
class PermissionDenied(APIException):
|
||||||
status_code = status.HTTP_403_FORBIDDEN
|
status_code = status.HTTP_403_FORBIDDEN
|
||||||
default_detail = 'You do not have permission to perform this action.'
|
default_detail = 'You do not have permission to perform this action.'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user