问题描述
我正在编写采用JSON Web令牌(JWT)且必须检查令牌上的签名的Web端点。 因为我每次都要检查签名,所以对我来说最有意义的是,我应该将此步骤分解为一个函数,因为DRY。
但是,检查JWT是否正确签名的唯一方法是使用其秘密密钥对其进行解码并捕获错误。 这导致我执行以下功能:
def is_valid_token(token_string, secret_key):
try:
jwt.decode(token_string, secret_key)
return True
except jwt.DecodeError:
return False
就验证令牌而言,这可以很好地工作,但是,我拥有此功能来通过解码检查令牌是否有效似乎很浪费,然后在此功能之后我将不得不再次进行解码。 也就是说我会这样做:
if not is_valid_token(token_string, secret_key):
# Respond with an error to the client
else:
token_data = jwt.decode(token_string, secret_key)
在这种情况下,我正在解码以检查它是否有效,然后再次解码。 在C / C ++中,我将通过引用传递一个变量以捕获解码的数据,然后返回true或false。 有什么办法可以在Python中做这样的事情吗?
在我看来,我可以通过传递一个空列表来捕获解码的数据来解决这个问题,但这似乎确实很微不足道。 有没有Python的方法可以做到这一点?
1楼
与Nullman讨论之后,我们得出以下解决方案
def is_valid_token(jwt_string, secret_key, reference_list):
try:
data = jwt.decode(jwt_string, secret_key)
reference_list.append(data)
return True
except:
return False
reference_var = []
if not is_valid_token(jwt_string, secret_key, reference_var):
# Respond with an error to the client
else:
data = reference_var[0]
2楼
您的方法已经使用了良好的Pythonic 习惯用法,但是随后将其转换为C
风格的返回码检查模式。
不要那样做,请继续使用异常。
在这种情况下, is_valid_token
毫无意义;
当您仍然需要基于其返回值的if
/ else
时,它实际上不保存任何内容。
根本不进行测试,只需内联解析并在发生异常时处理异常:
try:
token_data = jwt.decode(token_string, secret_key)
except jwt.DecodeError:
# respond with error to client
else:
# Use token_data
它没有那么冗长的含义(如果没有其他方法可以引发jwt.DecodeError
,则可以通过将else
块的内容放入try
来使其更短,而它与if
/ else
一样冗长)。
如果这是在更深层的嵌套代码中,您甚至可能没有在这里捕获异常,而是让它冒泡地堆积在知道如何响应客户端的人收到它之前。
再次重申一下,您的问题是尝试使用LBYL惯用语来查看是否允许您执行某项操作,然后执行操作,而最简单的方法是仅执行该操作并在发生异常时对其进行处理。 实际上,您并没有避免使用DRY,因为在分析返回结果并使用结果时,RY最终代替了RY。
3楼
编辑:正如@ShadowRanger指出的那样,下面的代码应该可以工作,但实际上并没有任何改善,需要从__init__
引发异常,并且调用者需要对其进行检查。
所以这个包装器并没有真正的帮助。
我将答案参考,但是正确的方法可能是 。
也许您可以在这里利用类继承:
class WebEndPoint(object):
def __init__(self, token_string, secret_key)
try:
self.data = jwt.decode(token_string, secret_key)
except jwt.DecodeError as e:
# respond with "invalid token"
raise e
然后在您的代码中,可以使用类似以下的类:
class MyEndpoint(WebEndPoint):
def handle_request(self,...):
# do something with self.data, which you know is
# valid if you reach this point
myendpoint = MyEndPoint(token, secret)
这样,您甚至根本不需要调用is_valid()
,但是实际实现方式可能取决于您使用的框架(如果有)。