验证用户名和密码,验证成功后,为用户签发JWT,前端将签发的JWT保存下来。
请求方式: 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"
}
# 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()方法。
# 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),
}
JWT扩展的登录视图,在收到用户名与密码时,也是调用Django的认证系统中提供的**authenticate()**来检查用户与密码是否正确。
我们可以通过修改Django认证系统的认证后端(主要是authenticate方法)来支持登录账号既可以是用户名也可以是手机号。
修改Djnago认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackend, 并重写authenticate方法。
authenticate(self, request, username=None, password=None, **kwargs)方法的参数说明:
我们想要让用户既可以以用户名登录,也可以以手机号登录,那么对于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',
]