django restframework使用redis实现token认证

目录
  • 一、前言
  • 二、详解
    • 1. 前期准备
    • 2. 配置redis
    • 3. 将token写入redis
      • 3.1 原来的登录代码
      • 3.2 重写后的登录代码
      • 3.3 登录后redis存储的用户记录
    • 4. 重写认证token方法
      • 4.1 源码分析
      • 4.2 进行重写
      • 4.3 加入认证配置
      • 4.4 效果展示
  • 三、总结

一、前言

restframework有自己很方便的一套认证、权限体系:官方文档(tokenauthentication)

官方文档的token 是基于数据库中的authtoken_token表来做的

有时候在后续接口中需要使用的用户信息过多时,频繁、高并发下的查询数据库会带来比较大的性能消耗。这个时候我们就需要通过redis来做用户认证,并存储一些用户信息在其中。下面就为你讲解如何基于redis来使用DRF做用户认证。

二、详解

1. 前期准备

1.1 安装redis并启动

自行安装!这个都装不好后面的教程也不用看了!看了也理解不了!

1.2 安装django-redis库

pip install django-redis -i https://pypi.tuna.tsinghua.edu.cn/simple

2. 配置redis

2.1 配置redis连接

settings.py输入下面的代码 (我的redis没有设置密码,所以配置代码中无密码相关配置)

# redis缓存配置
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor",
            "IGNORE_EXCEPTIONS": True,
        }
    }
}

2.2 初始化redis连接

在项目初始化文件中(__init__.py)加入下面代码进行redis的初始化

加入下列代码

from django_redis import get_redis_connection
redis_connect = get_redis_connection()

3. 将token写入redis

在之前的登录接口是将token写入数据库的,现在需要重写它让其写入redis

3.1 原来的登录代码

@api_view(['POST'])
def login(request):
    """
    登录接口
    """
    user = authenticate(username=request.data['username'], password=request.data['password'])
    if user:
        Token.objects.filter(user_id=user.id).delete()
        token = Token.objects.create(user=user)
        _dict = {'id': user.id, 'username': user.username, 'first_name': user.first_name,
                 'last_name': user.last_name, 'email': user.email}
        redis_connect.set(token.key, json.dumps(_dict), 259200)  # 存redis 259200秒=72个小时
        return Response(data={'status_code': 200, 'msg': '登录成功!', 'token': token.key})
    return Response(data={'status_code': 403, 'msg': '密码错误!'})

3.2 重写后的登录代码

@api_view(['POST'])
def login(request):
    """
    登录接口
    """
    user = authenticate(username=request.data['username'], password=request.data['password'])
    if user:
        token = binascii.hexlify(os.urandom(20)).decode()  # 生成token 的方式
        _dict = {'id': user.id, 'username': user.username, 'first_name': user.first_name,
                 'last_name': user.last_name, 'email': user.email}
        redis_connect.set(token, json.dumps(_dict), 259200)  # 存redis 259200秒=72个小时
        return Response(data={'status_code': 200, 'msg': '登录成功!', 'token': token})
    return Response(data={'status_code': 403, 'msg': '密码错误!'})

3.3 登录后redis存储的用户记录

4. 重写认证token方法

4.1 源码分析

我们可以全局搜索TokenAuthentication 找到【restframework】源码中的Token认证类

这个类中我们只需要关注authenticate_credentials这个方法就可以了。

    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 (源码中的key) 去数据库中寻找是否有该对应的记录
如果有则认证成功返回usertoken这两个模型对象

如果没有对应的记录,则抛出【invalid token】异常

        try:
            token = model.objects.select_related('user').get(key=key)
        except model.DoesNotExist:
            raise exceptions.AuthenticationFailed(_('Invalid token.'))

如果有对应的记录,但用户是未激活的 (is_active=0) 则抛出【User inactive or deleted】异常

      if not token.user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))

然后restframework会在视图层的dispatch方法中进行异常的封装并返回响应结果。

4.2 进行重写

经过源码分析,我们需要重写的有两部分:

1.验证token (源码中的key) 是否有效,之前是从数据库进行验证的现在需要通过redis去验证

2.重新封装user模型对象,但有个问题需要注意的是:
如果你重写了django的user对象,让它关联了其他表的属性,那么这里则不能将其封装进user这个对象的,因为redis不能存储一个对象!,当然如果非要这么做可以将外键id值在登录 (写入token) 的时候存入redis,然后在这里通过该外键id去查询关联的外键表获取属性,再封装到user模型对象中!

重写后的代码

class RedisTokenAuthentication(TokenAuthentication):

    def authenticate_credentials(self, key):
        null = None  # json的None为null,所以需要定义一下
        user_data = redis_connect.get(key)
        if user_data:
            user_dict = json.loads(user_data)
            user_obj = User()
            for key_name in user_dict.keys():
                setattr(user_obj, key_name, user_dict[key_name])
            return user_obj, key
        raise exceptions.AuthenticationFailed(_('无效的token.'))

4.3 加入认证配置

settings.py配置文件中,加入如下配置

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (  #如果有REST_FRAMEWORK配置项了单独加入该项即可
        'Demo.RedisAuthentication.RedisTokenAuthentication',  # 项目名称.重新认证类所在的文件.类名
    ),
}

4.4 效果展示

增加一个接口

path('test-token', views.test_token),

接口方法代码

@api_view(['GET'])
@permission_classes((permissions.IsAuthenticated,))
def test_token(request):
    """
    测试token
    """
    print('登录的用户名是:', request.user)
    res_data = {'data': {'status_code': 200}}
    return Response(**res_data)

输出结果

登录的用户名是: admin

三、总结

无论是django还是restframework,他们的源码和官方文档在我看来是非常清晰的 (在我看的那么多官方文档中算很清晰的了) 这里给DRF的团队点个赞!!!

到此这篇关于django restframework使用redis实现token认证的文章就介绍到这了,更多相关django restframework token认证内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Django restframework 源码分析之认证详解

    前言 最近学习了 django 的一个 restframework 框架,对于里面的执行流程产生了兴趣,经过昨天一晚上初步搞清楚了执行流程(部分方法还不太清楚),于是想详细的总结一下当来一个请求时,在该框架里面是如何执行的? 启动项目时 昨天在调试django时,发现在 APIView 中打的断点没有断下来,而是打在 View 中的断点断下来了,调试了很多次,最后发现,在 django 项目启动时,会首先加载 urls 中的文件,执行 views 中类的 as_view方法,其实是继承自 API

  • Django restframework 框架认证、权限、限流用法示例

    本文实例讲述了Django restframework 框架认证.权限.限流用法.分享给大家供大家参考,具体如下: 概述 Django Rest Framework 是一个强大且灵活的工具包,使用Django REST Framework可以在Django的基础上迅速实现API,用以构建Web API. 认证Authentication 可以在配置文件中配置全局默认的认证方案 REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest

  • DjangoRestFramework 使用 simpleJWT 登陆认证完整记录

    本文为 djangorestframework-simplejwt 使用记录.(官方文档) 1. 安装 pip install djangorestframework-simplejwt 2. 使用 创建 Django 项目及 app: # 创建名为 simple 的工程 django-admin startproject simple # 创建名为 users 的应用 cd simple python manage.py startapp users 目录结构如下: 在 `simple/set

  • django restframework使用redis实现token认证

    目录 一.前言 二.详解 1. 前期准备 2. 配置redis 3. 将token写入redis 3.1 原来的登录代码 3.2 重写后的登录代码 3.3 登录后redis存储的用户记录 4. 重写认证token方法 4.1 源码分析 4.2 进行重写 4.3 加入认证配置 4.4 效果展示 三.总结 一.前言 restframework有自己很方便的一套认证.权限体系:官方文档(tokenauthentication) 官方文档的token 是基于数据库中的authtoken_token表来做

  • SpringBoot和Redis实现Token权限认证的实例讲解

    一.引言 登陆权限控制是每个系统都应必备的功能,实现方法也有好多种.下面使用Token认证来实现系统的权限访问. 功能描述: 用户登录成功后,后台返回一个token给调用者,同时自定义一个@AuthToken注解,被该注解标注的API请求都需要进行token效验,效验通过才可以正常访问,实现接口级的鉴权控制. 同时token具有生命周期,在用户持续一段时间不进行操作的话,token则会过期,用户一直操作的话,则不会过期. 二.环境 SpringBoot Redis(Docke中镜像) MySQL

  • django restframework序列化字段校验规则

    目录 一.怎么校验创建的项目名是否是唯一的,当项目名name字段不唯一,怎么设置提示信息? 二.项目名称中必须得包含“项目”2字 三.单个字段进行校验:项目名称不能多于10个字 四.多字段进行校验: 五.to_internal_value方法,是所有字段开始进行校验时的入口方法(最先调用的方法) 六.to_representation方法,是序列化输出的入口方法 一.怎么校验创建的项目名是否是唯一的,当项目名name字段不唯一,怎么设置提示信息? class ProjectsSerializer

  • Java实现基于token认证的方法示例

    随着互联网的不断发展,技术的迭代也非常之快.我们的用户认证也从刚开始的用户名密码转变到基于cookie的session认证,然而到了今天,这种认证已经不能满足与我们的业务需求了(分布式,微服务).我们采用了另外一种认证方式:基于token的认证. 一.与cookie相比较的优势: 1.支持跨域访问,将token置于请求头中,而cookie是不支持跨域访问的: 2.无状态化,服务端无需存储token,只需要验证token信息是否正确即可,而session需要在服务端存储,一般是通过cookie中的

  • Laravel5.4简单实现app接口Api Token认证方法

    我是小白,今天写这篇文章主要是给新手学习看的,大佬就不用看了,有很多不足望大家指出,共同进步. 在开发中许多 API 通常在返回响应之前都需要某种形式的认证,有些时候,一个认证的请求和一个未认证的请求,响应可能不同. 在web项目中,实现认证比较轻松,那么前后端分离的项目中,我们要怎么实现认证,今天这篇文章就以 API token 认证机制,使用Token可以解决laravel API的无状态认证. 一.给用户表users增加api_token字段 php artisan make:migrat

  • docker django无法访问redis容器的解决方法

    docker-compose.yal文件中: redis: image: redis container_name: xdemo.redis ports: - 6379:6379 restart: always django setting.py中配置redis: CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', 'LOCATION': 'redis://127.0.0.1:6379', "OPTIONS&qu

  • 基于redis实现token验证用户是否登陆

    基于项目需求, 我们要实现一个基于redis实现token登录验证,该如何实现呢: 后端实现: 1.引入redis相关的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupI

  • vue路由导航守卫和请求拦截以及基于node的token认证的方法

    什么时候需要登录验证与权限控制 1.业务系统通常需要登录才能访问受限资源,在用户未登录情况下访问受限资源需要重定向到登录页面: 2.多个业务系统之间要实现单点登录,即在一个系统或应用已登录的情况下,再访问另一个系统时不需要重复登录:在登录过期或失效时,需要重定向到登录页面 如何使用路由守卫 定义一个index.js页面用来定义页面的路由,代码如下: import Vue from 'vue' import Router from 'vue-router' import blogIndex fro

随机推荐