Django REST框架-为自定义JWT身份验证重写JSONWebTokenAuthentication
我有一个带有外部数据库的Django应用程序,这意味着对于每个用户请求,我都向外部DB服务器发送SQL查询。不存在本地数据库(如sqllite等)。此外,JWT还应用于对用户进行身份验证。 为此,我已覆盖了Django REST框架-为自定义JWT身份验证重写JSONWebTokenAuthentication,django,authentication,jwt,Django,Authentication,Jwt,我有一个带有外部数据库的Django应用程序,这意味着对于每个用户请求,我都向外部DB服务器发送SQL查询。不存在本地数据库(如sqllite等)。此外,JWT还应用于对用户进行身份验证。 为此,我已覆盖了获取JSONWebToken视图: class ObtainJWT(ObtainJSONWebToken): def post(self, request, *args, **kwargs): username = request.data.get('username'
获取JSONWebToken
视图:
class ObtainJWT(ObtainJSONWebToken):
def post(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
# verify that user with given credentials exist in db
resp = requests.post(settings.SERVER_HOST+"/auth/",
json={"username":username, "password":password})
if resp.status_code == status.HTTP_401_UNAUTHORIZED:
return Response({'error':'Invalid credentials'},
status=status.HTTP_401_UNAUTHORIZED)
# create token
payload = jwtutils.jwt_payload_handler(username, password, api_settings.JWT_EXPIRATION_DELTA)
token = jwt_encode_handler(payload)
return Response({'token': token},
status=status.HTTP_200_OK)
和jwtutils
中的jwt\u有效载荷处理程序
:
def jwt_payload_handler(username, password, delta):
# custom payload handler
payload = {
'username': username,
'password': password,
'exp': datetime.utcnow() + delta
}
return payload
现在我可以不使用任何用户
对象成功获取令牌。但是当使用获得的令牌时(用户尝试使用令牌访问受保护的路由),{“detail”:“Invalid signature.”}
返回。我认为这是因为我使用的DRF的JSONWebTokenAuthentication
类有authenticate\u credentials
方法来检查本地数据库()中是否存在具有给定凭据的用户,因此出现了错误。所以我决定创建自定义身份验证类。
下面是我写的:
class JSONWebTokenAuthentication(BaseAuthentication):
"""
Token based authentication using the JSON Web Token standard.
"""
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(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()
return (None, payload)
然而,这是行不通的。我返回的是None
而不是有效的User
对象。在Django的身份验证过程的稍后某个地方,如果值已通过身份验证()
返回True
,则读取并测试该值。返回None
显然会导致{“详细信息”:“您没有执行此操作的权限”。}
我对Django和JWT比较陌生,重写身份验证类的最佳方法是什么,这样我就不会在本地保存任何Django
User
s,也不会破坏Django身份验证过程中的任何内容?或者我需要重写一些权限类?提前感谢。不确定您是否解决了此问题,但您是否在rest框架设置中添加了自定义身份验证类?大概是这样的:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'myapp.location.JSONWebTokenAuthentication' #location of your custom authentication class.
),
}