python学习之美多商城(七):用户部分--账号登录与多账号登录

一、账号登录:

1. 业务说明

验证用户名和密码,验证成功后,为用户签发JWT,前端将签发的JWT保存下来。
python学习之美多商城(七):用户部分--账号登录与多账号登录_第1张图片

4.后端接口分析:

请求方式: POST authorizations/
请求参数: JSON或表单

参数名 类型 是否必须 说明
username str 用户名
password str 密码

返回值: JSON

返回值 类型 是否必须 说明
username str 用户名
user_id str 用户id
token str jwt_token(作状态保持)
{
    "username": "python",
    "user_id": 1,
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo5LCJ1c2VybmFtZSI6InB5dGhvbjgiLCJleHAiOjE1MjgxODI2MzQsImVtYWlsIjoiIn0.ejjVvEWxrBvbp18QIjQbL1TFE0c0ejQgizui_AROlAU"
}

3.业务分析:

  • 登录后需要jwt token做状态保持,而且在Django REST framework JWT中恰恰提供了公户验证登录功能.。python学习之美多商城(七):用户部分--账号登录与多账号登录_第2张图片
  • 在users/urls中,使用JWT提供的路由方法,登陆后实现了状态保持,但是在用户名位置没有显示用户名 在这里插入图片描述,查看登录页面js代码,发现后端只返回了token,python学习之美多商城(七):用户部分--账号登录与多账号登录_第3张图片
    这是不能满足需求,所以我们要重写JWT提供的登录验证方法。
    -通过查看JWT的源码可知,
# obtain_jwt_token = ObtainJSONWebToken.as_view()
# ==> class ObtainJSONWebToken(JSONWebTokenAPIView):
class JSONWebTokenAPIView(APIView):
    """
    Base API View that various JWT interactions inherit from.
    """
    ...
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        if serializer.is_valid():
            user = serializer.object.get('user') or request.user
            token = serializer.object.get('token')
            response_data = jwt_response_payload_handler(token, user, request)
            response = Response(response_data)
            if api_settings.JWT_AUTH_COOKIE:
                expiration = (datetime.utcnow() +
                              api_settings.JWT_EXPIRATION_DELTA)
                response.set_cookie(api_settings.JWT_AUTH_COOKIE,
                                    token,
                                    expires=expiration,
                                    httponly=True)
            return response

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        ...

中的 response_data = jwt_response_payload_handler(token, user, request) 方法是生成响应数据的方法,默认只返回token,因此要重写jwt_response_payload_handler()方法。

  • 当然在JWT的官方文档中也给出了说明: python学习之美多商城(七):用户部分--账号登录与多账号登录_第4张图片

4.重写JWT的验证方法:

# users/utils.py
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        'user_id':user.id,
        'username':user.username
    }

指定属性,告诉JWT要是用自定义返回参数的方法,进行结果返回。

# meiduo_mall/settings/dev.py 添加
# 指定JWT属性
JWT_AUTH = {
    # 返回属性设置
    'JWT_RESPONSE_PAYLOAD_HANDLER':
    'users.utils.jwt_response_payload_handler',
    # token有效期配置
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
}

5. 增加支持用户名与手机号均可作为登录账号:

JWT扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的**authenticate()**来检查用户与密码是否正确。
我们可以通过修改Django认证系统的认证后端(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。
修改Djnago认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend, 并重写authenticate方法。
authenticate(self, request, username=None, password=None, **kwargs)方法的参数说明:

  • request 本次认证的请求对象
  • username 本次认证提供的用户账号
  • password 本次认证提供的密码

我们想要让用户既可以以用户名登录,也可以以手机号登录,那么对于authenticate方法而言,username参数即表示用户名或者手机号。

重写authenticate方法的思路:

  1.根据username参数查找用户User对象,username参数可能是用户名,也可能是手机号;
  2.若查找到User对象,调用User对象的check_password方法检查密码是否正确;

#users/utils.py
class UsernameMobileAuthorBackend(ModelBackend):
    """
    自定义用户名或手机号认证
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        验证用户名或手机号,返回用户对象
        :param request: 
        :param username: 
        :param password: 
        :param kwargs: 
        :return: 
        """
        try:
            if re.match("r1[3-9]\d{9}$", username):
                user = User.objects.get(mobile=username)
            else:
                user=User.objects.get(username=username)
        except:
            user = None
        # 判断密码.使用django的用户模块自带的方法
        if user is not None and user.check_password(password):
            return user

在配置文件中告知Django使用我们自定义的认证后端

# settings/dev.py
# 用户验证逻辑
AUTHENTICATION_BACKENDS = [
    'users.utils.UsernameMobileAuthBackend',
]

你可能感兴趣的:(Web,DRF框架,python学习,Django,web项目开发)