主要是因爲,登錄時生成token時,源碼是利用username和password生成的,如果需要其它方式登錄,必須修改生成和解析token的方法;重定義以下類。重定義結束後,在setting中修改jwt驗證token的類,還需要修改登錄時的token 的方法。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'verifications.authentication.JSONWebTokenAuthentication',
),
}
重定義文件
import jwt
from datetime import datetime
from calendar import timegm
from rest_framework import exceptions
from rest_framework_jwt.settings import api_settings
from django.utils.encoding import smart_text
from rest_framework.authentication import (
BaseAuthentication, get_authorization_header
)
from django.utils.translation import ugettext as _
import users
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
class BaseJSONWebTokenAuthentication(BaseAuthentication):
"""
Token based authentication using the JSON Web Token standard.
"""
def get_jwt_value(self, request):
pass
def authenticate(self, request):
"""
Returns a two-tuple of `User` and token if a valid signature has been
supplied using JWT-based authentication. Otherwise returns `None`.
"""
jwt_value = self.get_jwt_value(request)
if jwt_value is None:
return None
try:
payload = jwt_decode_handler(jwt_value)
except jwt.ExpiredSignature:
msg = _('Signature has expired.')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()
user = self.authenticate_credentials(payload)
return user, jwt_value
def authenticate_credentials(self, payload):
"""
Returns an active user that matches the payload's user id and email.
"""
# User = get_user_model()
# username = jwt_get_username_from_payload(payload)
mobile = payload.get('mobile') # 如果更新用戶信息時更改到手機號,則要重新登錄獲取新的token
if not mobile:
msg = _('Invalid payload.')
raise exceptions.AuthenticationFailed(msg)
try:
# user = User.objects.get_by_natural_key(username)
user = users.models.QcUser.objects.get(mobile=mobile)
except users.models.QcUser.DoesNotExist:
msg = _('Invalid signature.')
raise exceptions.AuthenticationFailed(msg)
# if not user.is_active:
# msg = _('User account is disabled.')
# raise exceptions.AuthenticationFailed(msg)
return user
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
"""
Clients should authenticate by passing the token key in the "Authorization"
HTTP header, prepended with the string specified in the setting
`JWT_AUTH_HEADER_PREFIX`. For example:
Authorization: JWT eyJhbGciOiAiSFMyNTYiLCAidHlwIj
"""
www_authenticate_realm = 'api'
def get_jwt_value(self, request):
auth = get_authorization_header(request).split()
auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
if not auth:
if api_settings.JWT_AUTH_COOKIE:
return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
return None
if smart_text(auth[0].lower()) != auth_header_prefix:
return None
if len(auth) == 1:
msg = _('Invalid Authorization header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid Authorization header. Credentials string '
'should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
return auth[1]
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
return '{0} realm="{1}"'.format(api_settings.JWT_AUTH_HEADER_PREFIX, self.www_authenticate_realm)
def jwt_payload_handler(user, exp=datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA):
username = user.username
payload = {'user_id': user.id, 'username': username, 'mobile': user.mobile, 'exp': exp}
# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)
if api_settings.JWT_AUDIENCE is not None:
payload['aud'] = api_settings.JWT_AUDIENCE
if api_settings.JWT_ISSUER is not None:
payload['iss'] = api_settings.JWT_ISSUER
return payload