此身份验证方案使用HTTP基自己份验证,根据用户的用户名和密码进行签名。基自己份验证一般仅适用于测试。html
若是成功经过身份验证,请BasicAuthentication
提供如下凭据。nginx
.request.user
将是一个Django User
实例。 ajax
.request.auth
会的None
。数据库
拒绝许可的未经身份验证的响应将致使HTTP 401 Unauthorized
使用适当的WWW-Authenticate标头进行响应。例如:apache
WWW-Authenticate: Basic realm="api"
注意:若是您BasicAuthentication
在生产中使用,则必须确保您的API仅可用于https
。您还应该确保您的API客户端始终在登陆时从新请求用户名和密码,而且永远不会将这些详细信息存储到持久存储中。django
此身份验证方案使用基于令牌的简单HTTP身份验证方案。令牌认证适用于客户端 - 服务器设置,例如本机桌面和移动客户端。后端
要使用该TokenAuthentication
方案,您须要配置要包含的身份验证类TokenAuthentication
,并rest_framework.authtoken
在您的INSTALLED_APPS
设置中另外包含:api
INSTALLED_APPS = ( ... 'rest_framework.authtoken' )
注意:确保manage.py migrate
在更改设置后运行。该rest_framework.authtoken
应用程序提供Django数据库迁移。安全
此身份验证方案使用Django的默认会话后端进行身份验证。会话身份验证适用于与您的网站在同一会话上下文中运行的AJAX客户端。服务器
若是成功经过身份验证,请SessionAuthentication
提供如下凭据。
request.user
将是一个Django User
实例。request.auth
会的None
。 未经许可的未经身份验证的响应将致使HTTP 403 Forbidden
响应。
若是您使用的是AJAX风格的API与SessionAuthentication,你须要确保你有一个有效的CSRF令牌任何“不安全”的HTTP方法调用,如PUT
,PATCH
,POST
或DELETE
请求。有关更多详细信息,请参阅Django CSRF文档。
警告:建立登陆页面时始终使用Django的标准登陆视图。这将确保您的登陆视图获得适当保护。
REST框架中的CSRF验证与标准Django的工做方式略有不一样,由于须要同时支持基于会话和非会话的身份验证。这意味着只有通过身份验证的请求才须要CSRF令牌,而且能够在没有CSRF令牌的状况下发送匿名请求。此行为不适用于登陆视图,登陆视图应始终应用CSRF验证。
此身份验证方案容许您将身份验证委派给Web服务器,该服务器设置REMOTE_USER
环境变量。
要使用它,您必须django.contrib.auth.backends.RemoteUserBackend
在您的AUTHENTICATION_BACKENDS
设置中拥有(或子类) 。默认状况下,为尚不存在的用户名RemoteUserBackend
建立User
对象。要更改此行为和其余行为,请参阅 Django文档。
若是成功经过身份验证,请RemoteUserAuthentication
提供如下凭据:
request.user
将是一个Django User
实例。request.auth
会的None
。有关配置身份验证方法的信息,请参阅Web服务器的文档,例如:
要实现自定义身份验证方案,请子类化BaseAuthentication
并覆盖该.authenticate(self, request)
方法。(user, auth)
若是身份验证成功,则该方法应返回两元组,None
不然返回。
在某些状况下None
,您可能但愿AuthenticationFailed
从该.authenticate()
方法引起异常,而不是返回。
一般,您应采起的方法是:
None
。还将检查还在使用的任何其余身份验证方案。AuthenticationFailed
异常。不管是否进行任何权限检查,都将当即返回错误响应,而且不会检查任何其余身份验证方案。 您也能够覆盖该.authenticate_header(self, request)
方法。若是实现,它应返回一个字符串,该字符串将用做响应WWW-Authenticate
中标头的值HTTP 401 Unauthorized
。
若是.authenticate_header()
未覆盖该方法,则在HTTP 403 Forbidden
拒绝未经身份验证的请求访问时,身份验证方案将返回响应。
注意:当请求对象.user
或.auth
属性调用您的自定义身份验证器时,您可能会看到AttributeError
从新提高为WrappedAttributeError
。这是防止外部属性访问抑制原始异常所必需的。Python不会识别AttributeError
来自自定义身份验证器的orginates,而是假设请求对象没有.user
或.auth
属性。这些错误应由您的验证者修复或以其余方式处理。
2.1setting.py中的install-app添加app:
#Token验证,会生成表
'rest_framework.authtoken',
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', #添加Token验证,若是Token过时,不须要登陆的界面也不能访问,最好配置在具体的页面 ),
生成token表,用户登陆后会建立对应的key
2.2使用时TokenAuthentication
,您可能但愿为客户端提供一种机制,以获取给定用户名和密码的令牌。REST框架提供了一个内置视图来提供此行为。要使用它,请将obtain_auth_token
视图添加到URLconf:
from rest_framework.authtoken import views #配置url urlpatterns += [ url(r'^api-token-auth/', views.obtain_auth_token) ]
2.3Django请求到响应全过程:http://www.projectsedu.com/
2.4TokenAuthentication源码:
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
经过该函数获取Token并返回
def authenticate(self, request): auth = get_authorization_header(request).split() if not auth or auth[0].lower() != self.keyword.lower().encode(): return None if len(auth) == 1: msg = _('Invalid token header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: msg = _('Invalid token header. Token string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: token = auth[1].decode() except UnicodeError: msg = _('Invalid token header. Token string should not contain invalid characters.') raise exceptions.AuthenticationFailed(msg) return self.authenticate_credentials(token)
而后经过authenticate判断token是否合法
def authenticate_credentials(self, key): model = self.get_model() try: token = model.objects.select_related('user').get(key=key) except model.DoesNotExist: raise exceptions.AuthenticationFailed(_('Invalid token.')) if not token.user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (token.user, token)
到token表中查找是否对应token
IsAuthenticated:该IsAuthenticated
许可类将拒绝容许任何未认证用户,并容许许可,不然。若是您但愿您的API仅供注册用户访问,则此权限适用。
IsAdminUser:所述IsAdminUser
许可类将拒绝许可给任何用户,除非user.is_staff
是True
在这种状况下的许可将被容许。若是您但愿只有可信管理员的子集能够访问您的API,则此权限是合适的。
IsAuthenticatedOrReadOnly:这IsAuthenticatedOrReadOnly
将容许通过身份验证的用户执行任何请求。只有在请求方法是“安全”方法之一时,才容许对未经受权的用户提出请求; GET
,HEAD
或OPTIONS
。若是您但愿API容许匿名用户具备读取权限,而且仅容许对通过身份验证的用户具备写入权限,则此权限是合适的。
如下是根据黑名单检查传入请求的IP地址的权限类的示例,若是IP已被列入黑名单,则拒绝该请求。
from rest_framework import permissions class BlacklistPermission(permissions.BasePermission): """ Global permission check for blacklisted IPs. """ def has_permission(self, request, view): ip_addr = request.META['REMOTE_ADDR'] blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() return not blacklisted
除了针对全部传入请求运行的全局权限以外,您还能够建立对象级权限,这些权限仅针对影响特定对象实例的操做运行。例如:
class IsOwnerOrReadOnly(permissions.BasePermission): """ Object-level permission to only allow owners of an object to edit it. Assumes the model instance has an `owner` attribute. """ def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True # Instance must have an attribute named `owner`. return obj.owner == request.user
自定义验证(能够新建一个文件):
from rest_framework import permissions class IsOwnerOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): # Read permissions are allowed to any request, # so we'll always allow GET, HEAD or OPTIONS requests. if request.method in permissions.SAFE_METHODS: return True # Instance must have an attribute named `owner`. return obj.user == request.user
views中使用验证:
...... from utils.permissions import IsOwnerOrReadOnly # Create your views here. class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): ''' list: 获取用户收藏列表 retrieve: 判断某个商品是否收藏 create: 收藏商品 ''' # queryset = UserFav.objects.all() permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) ......
from rest_framework import permissions from rest_framework import authentication from rest_framework_jwt.authentication import JSONWebTokenAuthentication ...... class UserViewset(mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet): ''' 用户 ''' serializer_class = UserRegSerializer queryset = User.objects.all() authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication) #更新,添加用户信息放在一块儿,是否登陆应该动态,注册不用登陆IsAuthenticated,该方法不行 # permission_classes = (permissions.IsAuthenticated) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user=self.perform_create(serializer) re_dict=serializer.data payload=jwt_payload_handler(user) re_dict['token']=jwt_encode_handler(payload) re_dict['name']=user.name if user.name else user.username headers = self.get_success_headers(serializer.data) return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) def get_serializer_class(self): ''' 重载GenericAPIView中的get_serializer_class函数,调用不一样的序列化类,若是是create, 就调用UserRegSerializer序列化,不然UserDetailSerializer序列化 :return: ''' if self.action == 'retrieve': return UserDetailSerializer elif self.action == 'create': return UserRegSerializer return UserDetailSerializer def get_permissions(self): ''' 重载APIview中的get_perimissions函数,若是是新增用户则不用登陆,不然必须登陆 :return: ''' if self.action == 'retrieve': return [permissions.IsAuthenticated()] elif self.action == 'create': return [] return [] def get_object(self): ''' 返回当前用户 :return: ''' return self.request.user def perform_create(self, serializer): return serializer.save()