django authentication_classes自定义权限验证类 authenticate

什么是身份认证

身份验证是将传入请求与一组标识凭据(例如请求来自的用户或与其签名的令牌)关联的机制。

视图的最开始处运行身份验证

在权限和限制检查发生之前,以及在允许继续执行任何其他代码之前,始终在视图的最开始处运行身份验证。

身份验证方案总是定义为类的列表

REST框架尝试对列表中的每个类进行身份验证,并将成功身份验证的第一个类的返回值赋值给request.user ,request.auth。 如果没有类身份验证,则request.user将设置为django.contrib.auth.models.anonymousUser的实例,request.auth将设置为none。

 

验证的执行过程

1、在APIView中重写 dispatch方法,方法最后有一段描述:    

# Ensure that the incoming request is permitted       确保传入进来的

request是被允许的 self.perform_authentication(request)  #执行验证

self.check_permissions(request)         #检查全选

self.check_throttles(request)         #检查阀门

2、def perform_authentication(self, request): request.user

这个方法只有这么一句话 获取user 其实这是Request类的一个user方法

3、@property

def user(self): 走到 def _authenticate(self):

方法 在这个方法中有   for authenticator in self.authenticators:

            user_auth_tuple = authenticator.authenticate(self)

表示遍历我们设置的authentication_classes属性中的所有验证类列表,每个验证类都去执行类中的authenticate()方法。

举例:

         开发模式为DRF框架(django rest framework) 前后端分离开发模式,用token作为认证方式。所以就需要实现一个类似于 登录装饰器的功能模块,django中自带有authentication_classes,因为每一个项目的验证token逻辑都不一样,所以这里需要开发者自定义,代码如下:

# 自定义的认证类  以token为例
class Authentication(APIView):
    # token认证函数
    def authenticate(self, request):
        token = request.GET.get('token')
        if not token:
            token = request.data.get('token')
        token_user_list = SqlFun.select_token_valid_time(token)  # 获取token对应的信息
        # token_obj = UserToken.objects.filter(token=token).first()
        if len(token_user_list) == 0:
            ret = {'code': 1001, 'msg': '用户认证失败', 'result': None}
            raise exceptions.AuthenticationFailed(ret)
        else:
            valid_time = token_user_list[0].get("valid_time")
            now_time = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
            account = token_user_list[0].get("account")
            if now_time <= valid_time:  # token在有效期内
                # 更新token有效期
                valid_time_new = (datetime.datetime.now() + datetime.timedelta(minutes=60 * 8)).strftime(
                                  '%Y%m%d%H%M%S')  # 有效时间 现在时间+8小时
                SqlFun.mysql_insert_user_token_valid_time(account, token, valid_time_new)
                return account, token
            else:
                ret = {'code': 1002, 'msg': 'token过期,请重新登录', 'result': None}
                raise exceptions.AuthenticationFailed(ret)
                # 抛出异常就会返回response= ret格式的json串
        # 在rest framework内部会将这两个字段赋值给request,以供后续操作使用

        # getgps测试

        # return token_obj.user, token_obj


class fun1(APIView):
    """

    Args:
        APIView ([type]): [description]

    Returns:
        JsonRespone: [响应]
    """
    authentication_classes = [Authentication, ]  # 启动token验证
    def POST(self,request):
        pass

设计思路

其实所谓的token,就是一串加密的字符串

需求:用户登录访问页面后,在未退出登录账号的情况下,再次访问页面无需再次登录

首先我们抛开过期时间不管

设计思路:主要是前端有个缓存可以存取一些信息一段时间,所以

在注册时生成一串加密好的数字,连同用户信息一起添加到数据库的用户表中,token字段必须唯一
用户登录成功,查询出这个用户的token返回给前端保存起来
用户再次登录时,前端把保存起来的token传给后端,后端验证无误后,让用户无需再次输入账号密码登录就能访问页面

最重要的思想:token的有效期

首先得知道为什么要做token有效期。假如token生成后就一直不变,那么有一天被不速之客在前端页面获取到了用户的token,那么他则可以为所欲为了。所以为了防止token泄漏,我们得为token做一个有效期,一般为三天,如果用户三天都没有登录过,那么我们得让用户重新登录一下

主要是想好在哪里插入和更新token的有效期:

 在用户注册的时候插入token的有效期
在用户登录的时候更新token的有效期和token
用户每次访问页面时,判断token有效期是否过期:未过期则只更新token有效期,过期则同时更新token有效期和token


注:更新token有效期不一定要更新token哦!!过期或登录时才同时token,变一下token,你懂的

另一种写法

import pytz
from rest_framework.authentication import SessionAuthentication
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache
import datetime
from rest_framework.authentication import BaseAuthentication,TokenAuthentication
from rest_framework import exceptions
from rest_framework.authtoken.models import Token
from rest_framework import HTTP_HEADER_ENCODING

# 获取请求头里的token信息
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, type('')):
        # Work around django test client oddness
        auth = auth.encode(HTTP_HEADER_ENCODING)
    return auth

# 自定义的ExpiringTokenAuthentication认证方式
class ExpiringTokenAuthentication(BaseAuthentication):
    model = Token
    def authenticate(self, request):
        auth = get_authorization_header(request)

        if not auth:
            return None
        try:
            token = auth.decode()
        except UnicodeError:
            msg = _('Invalid token header. Token string should not contain invalid characters.')
            raise exceptions.AuthenticationFailed(msg)
        return self.authenticate_credentials(token)

    def authenticate_credentials(self, key):
        # 增加了缓存机制
      # 首先先从缓存中查找
        token_cache = 'token_' + key
        cache_user = cache.get(token_cache)
        if cache_user:
            return (cache_user.user, cache_user)  # 首先查看token是否在缓存中,若存在,直接返回用户
        try:
            token = self.model.objects.get(key=key[6:])

        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('认证失败')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('用户被禁止')

        utc_now = datetime.datetime.utcnow()

        if  (utc_now.replace(tzinfo=pytz.timezone("UTC")) - token.created.replace(tzinfo=pytz.timezone("UTC"))).days > 14:  # 设定存活时间 14天
            raise exceptions.AuthenticationFailed('认证信息过期')

        if token:
            token_cache = 'token_' + key
            cache.set(token_cache, token, 24 * 7 * 60 * 60)  # 添加 token_xxx 到缓存
        return (token.user, token)

    def authenticate_header(self, request):
        return 'Token'

 

觉的能帮到你就给个赞吧
 

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以回答这个问题。下面是一个简单的 Django JWT 登录验证代码示例: ```python from rest_framework.views import APIView from rest_framework.response import Response from rest_framework_jwt.settings import api_settings from rest_framework_jwt.authentication import JSONWebTokenAuthentication from rest_framework.permissions import IsAuthenticated jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER class LoginView(APIView): def post(self, request): username = request.data.get('username') password = request.data.get('password') # 在这里进行用户名和密码的验证验证通过后生成 token user = authenticate(username=username, password=password) if user is not None: payload = jwt_payload_handler(user) token = jwt_encode_handler(payload) return Response({'token': token}) else: return Response({'error': 'Invalid credentials'}) class ProtectedView(APIView): authentication_classes = (JSONWebTokenAuthentication,) permission_classes = (IsAuthenticated,) def get(self, request): return Response({'message': 'You are authenticated'}) ``` 在这个示例中,我们定义了两个视图:`LoginView` 和 `ProtectedView`。`LoginView` 用于处理用户登录请求,`ProtectedView` 用于测试 JWT 验证是否成功。 在 `LoginView` 中,我们首先获取用户提交的用户名和密码,然后进行验证。如果验证通过,我们使用 `jwt_payload_handler` 和 `jwt_encode_handler` 生成 JWT token,并将其返回给客户端。 在 `ProtectedView` 中,我们使用 `JSONWebTokenAuthentication` 进行 JWT 验证,并使用 `IsAuthenticated` 权限确保用户已经通过验证。如果用户已经通过验证,我们返回一个简单的消息。 这只是一个简单的示例,实际上,JWT 验证可能会更加复杂,具体取决于您的应用程序需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值