首页 > 其他分享 >改进django rest framework中的token验证,并加入cache

改进django rest framework中的token验证,并加入cache

时间:2023-05-21 23:32:21浏览次数:44  
标签:get cache auth token user key rest


      在用户验证方面用到token验证,这是一种安卓/iso/..手机客户端常用的,方便的验证方式。

原理是客户端给我发一段字符串,这段字符串是用户在注册,登入的时候、服务器生成的,并关联到用户。保存到数据库,然后返回给客户端,客户端之后呢,就可以凭借这个字符串来确认“我是我,不是别人”。而不用每次验证都要通过账号密码。 _ _ _

django-rest-framework 有一套默认的token验证机制dfs token验证 具体用法不再细讲了,官方文档写得很清楚。

但是笔者发现一个问题,这个token验证机制存的token,一旦生成就保持不变。这样就引发一些问题,万一某人拿到你的token不就为所欲为了吗,就像别人拿到你的密码一样。

解决方案: 给token设置过期时间,超过存活时间,这段token不再具有验证功能,每次用户重新登入,刷新token(这段新token的有存活时间)。这样,重新登入后,你的token更新了,某些居心不良的人即便拿着之前抢来的token也没用。stackoverflow上已经有了token过期时间的讨论。 参考他们的代码我这样写。

##改进



#coding=utf-8   auth.py
from django.utils.translation import ugettext_lazy as _
from django.core.cache import cache

import datetime

from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from account.models import Token
from rest_framework import HTTP_HEADER_ENCODING

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

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):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('认证失败')

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

        utc_now = datetime.datetime.utcnow()

        if token.created < utc_now - datetime.timedelta(hours=24 * 14):
            raise exceptions.AuthenticationFailed('认证信息过期')

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



还要配置settings文件



REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'yourmodule.auth.ExpiringTokenAuthentication',
    ),
}



##再改进 使用了cache缓存对token和关联的用户进行了缓存,因为token验证经常需要从数据库读取,加入缓存,大幅提高速度。



def authenticate_credentials(self, key):
    
    token_cache = 'token_' + key
    cache_user = cache.get(token_cache)
    if cache_user:
        return cache_user     # 首先查看token是否在缓存中,若存在,直接返回用户

    try:
        token = self.model.objects.get(key=key)
    except self.model.DoesNotExist:
        raise exceptions.AuthenticationFailed('认证失败')

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

    utc_now = datetime.datetime.utcnow()

    if token.created < utc_now - datetime.timedelta(hours=24 * 14):  # 设定存活时间 14天
        raise exceptions.AuthenticationFailed('认证信息过期')

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

    return (token.user, token)



我的login函数是这样写的



@api_view(['POST'])
def login_views(request):
    receive = request.data   
    if request.method == 'POST':
        username = receive['username']
        password = receive['password']
        user = auth.authenticate(username=username, password=password)
        if user is not None and user.is_active:
            # update the token
            token = Token.objects.get(user=user)  
            token.delete()
            token = Token.objects.create(user=user)
            user_info = UserInfo.objects.get(user=user)
            serializer = UserInfoSerializer(user_info)

            response = serializer.data             
            response['token'] = token.key

            return json_response({
                "result": 1,
                "user_info":response, # response contain user_info and token 
                })
        else:
            try:
                User.objects.get(username=username)
                cause = u'密码错误'
            except User.DoesNotExist:
                cause = u'用户不存在'

            return json_response({
                "result": 0,
                "cause":cause,
                })



 

标签:get,cache,auth,token,user,key,rest
From: https://blog.51cto.com/u_6186189/6320691

相关文章

  • 利用 Django REST framework 编写 RESTful API
        自动生成符合RESTful规范的API支持OPTION、HEAD、POST、GET、PATCH、PUT、DELETE根据 Content-Type生成browserable的交互页面(自动为API生成非常友好的浏览器页面)非常细粒度的权限管理(可以细粒度到field级别)示意图安装$pipinstalldjangorestframew......
  • Openresty 学习笔记(二)Nginx Lua 正则表达式相关API
    ngx.re.match语法: captures,err=ngx.re.match(subject,regex,options?,ctx?,res_table?)环境: init_worker_by_lua*,set_by_lua*,rewrite_by_lua*,access_by_lua*,content_by_lua*,header_filter_by_lua*,body_filter_by_lua*,log_by_lua*,ngx.timer.*,balancer......
  • 简单封装JWTUtils实现对token的创建和过期时间检查
    想要使用jwt需要先导入依赖<!--https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></depend......
  • 前端项目实战79-postgrest的增删改查简单文档
    Postgrest使用手册1过滤出is_delete=0的数据分页查询并按照id倒叙排列2GEThttp://127.0.0.1:3000/t_wms_location?is_delete=eq.0&limit=10&offset=23&order=id.desc仓库管理postgrest返回总页数:1......
  • 配置k8s的一个serviceaccount具有管理员权限并获取他的token
    创建sa账户/授定管理员角色权限cat>sa.yaml<<eofapiVersion:v1kind:ServiceAccountmetadata:name:kubepi-usernamespace:kube-systemeofcat>rolebe.yaml<<eofapiVersion:rbac.authorization.k8s.io/v1kind:ClusterRoleBindingmetadata:na......
  • 使用 Elasticsearch 的 REST API 来查询节点的内存使用情况
    curl-XGET'http://172.18.10.96:9200/_nodes/node-1/stats?pretty&human&filter_path=nodes.*.jvm.mem.heap_used_percent'{"nodes":{"WKECtNqYSuCKgHu-HNJTfg":{"jvm":{"mem":......
  • 一种基于token 和 Permission 的权限管理中间件示例
    1.先上封装后的使用效果[Permission(Key="/User/AddUser")][HttpPost]publicResultAddUser([FromBody]SaUseruser){//Dosth.thrownewNotImplementedException();}[Authorize]......
  • java调用python并且实现RESTAPI
    在Eclipse中创建springboot工程(maven)配置pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocati......
  • 【大数据】Presto(Trino)REST API 与执行计划介绍
    目录一、概述二、环境准备三、常用RESTAPI1)worker节点优雅退出2)提交SQL查询请求3)获取查询状态4)获取查询结果5)取消查询请求6)获取Presto节点信息7)获取Presto服务器使用统计信息8)获取查询计划四、Presto(Trino)执行计划一、概述Presto(现在叫Trino)是一个分布式SQL查询引擎,它允许......
  • Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken.
    @@CannotcastNewtonsoft.Json.Linq.JObjecttoNewtonsoft.Json.Linq.JToken 解决方法方法参数为[FromBody]objectcontent JObjectjo=(JObject)JsonConvert.DeserializeObject(content.ToString());JToken[]jtoArray=jo["contentBody"].ToArray();List<......