DRF框架之如何实现用户名和密码均可登录
由于我们经常会使用jwt_token保持用户的登录状态,所有Django RESTful Framework框架的扩展包 djangorestframework-jwt 帮我们在其内部实现了用户认证机制,即只需要在我们的路由中如下注册即可:
url(r'^authorizations/$',views.ObtainJSONWebToken.as_view())
那么这个视图主要帮我们做了哪些事情呢?
- 调用序列化器对用户名和密码进行校验,返回生成的 用户对象和 签发的jwt_token。
- 若校验成功,会签发一个jwt_token返回给前端,用来用户状态保持,返回响应。
一、其内部具体怎么实现呢?
还是直接看源码吧。
一、首先看 -- ObtainJSONWebToken 视图
通过文档介绍:
接收带有用户名和密码的post请求,返回一个jwt_token用于用户认证。
其继承了 JSONWebTokenAPIView 视图,而该视图 又继承了 APIView ,其主要帮我们实现了 POST方法。接下来我们看一下 该视图集的post方法。
二、JSONWebTokenAPIView 视图的post方法
从该方法中我们可以看到主要做了两个操作:
- 其调用了序列化器 对用户名和密码进行了校验并且返回数据(签发的jwt_token 和 user对象),而这个序列化器就是 上面看到的序列化器类 -- JSONWebTokenSerializer。
- 随后调用了一个函数 jwt_response_payload_handler(token, user, request),生成响应对象。
接下来我们看一下序列化器是怎样做 用户名和密码的校验的,和返回了什么样的数据?
三、JSONWebTokenSerializer的 validate 方法
其 主要实现的是:
- 通过其Django认证系统内部的一个 user = authenticate(**credentials) 实现 对 用户名和密码的校验 和 生成user对象 。
- 通过 用户对象 生成 jwt的payload部分,并且签发token。
- 返回 用户对象 和 token。(返回值会传入validated_data中,可以在视图中通过serializer.validated_data获取到。)
二、返回的响应数据
从上面的源码解析中我们可以了解到,生成响应数据的主要是 在 JSONWebTokenAPIView 中 post 方法中通过调用 jwt_response_payload_handler(token, user, request),来生成响应数据的。
那么需求来了,如果我想要给前端返回的不仅仅是 token,还有返回用户名、用户ID呢?
这时候我们就可以重写 jwt_response_payload_handler(token, user, request) 方法 去构建响应数据。
def jwt_response_payload_handler(token, user=None, request=None): """ 自定义jwt认证成功返回数据 """ return { 'token': token, 'user_id': user.id, 'username': user.username }
三、允许用户名和手机号均可登陆
通过上述源码介绍我们可以知道,其只允许使用 用户名 进行登录,其最终进行用户名和密码校验的还是调用Django的用户认证系统的 user = authenticate(**credentials)方法。
那么若我们想要 允许用户名和手机号均可登录 ,只需重写 authenticate(**credentials)方法 即可。例如:
def get_user_by_account(account): ''' 根据账号获取user对象 :param account: 账号,可以是用户名,也可以是手机好 :return: User对象或者None ''' try: if re.match(r'1[3-9]\d{9}$',account): # 说明是以手机号登陆 user = User.objects.get(mobile=account) else: # 说明是以用户名登陆 user = User.objects.get(username=account) except User.DoesNotExist: return None else: return user class UsernameMobileAuthBackend(ModelBackend): ''' 自定义用户名或者手机号 由于无论是restframework_jwt提供的认证还是其他均是调用了django中的ModelBackend的authenticate进行认证的, 故我们可以通过继承重写 -- 使得其既可以通过手机号又可以通过用户名进行登陆 ''' def authenticate(self, request, username=None, password=None, **kwargs): user = get_user_by_account(username) if user and user.check_password(password): return user else: return None # 没有返回值默认返回None
总结:
- 若使用 jwt_token做用户保持,DRF框架的提供了 用户认证视图类 -- ObtainJSONWebToken。
- 上述视图 通过序列化器进行 用户校验 并且 用户对象和 token,而其内部主要实现 用户名和密码校验的 还是调用Django的用户认证系统的 user = authenticate(**credentials)方法。
- 并且上述视图类中介绍post请求,通过调用序列化器做数据校验和数据转换,可以通过serializer.validated_data进行获取返回的数据,并且调用 jwt_response_payload_handler(token, user, request)方法生成响应数据。
over~~~,主要还是理解源码实现登录的逻辑~~~~~
本文来自博客园,作者:Little_five,转载请注明原文链接:https://www.cnblogs.com/littlefivebolg/p/9844727.html