我正在编写采用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中做这样的事情?
我突然意识到,我可以通过传入一个空列表来捕获解码数据,但这似乎真的很不优雅。是否有Pythonic方法来做到这一点?
答案 0 :(得分: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]
答案 1 :(得分:1)
你的方法已经使用了一个好的Pythonic EAFP成语,但它会把它变成C
样式LBYL返回码检查模式。不要这样做,继续使用例外。
在这种情况下,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
它没有更多的冗长(你可以通过将else
块的内容放在try
中,如果没有其他任何东西可以引发jwt.DecodeError
,那么它就可以缩短它。详细信息为if
/ else
)。
如果这是更深层嵌套的代码,你甚至可能不会在这里捕获异常,但让它冒泡堆栈,直到知道如何响应客户端的人收到它。
同样,重申一下,你的问题是尝试使用LBYL习语,看看你是否被允许做某事,然后去做,当最简单的方法是做它并处理异常(如果它发生)。你实际上没有避免DRY,因为在解析时不是RY,你在检查返回并使用结果时最终会RY。
答案 2 :(得分:1)
__init__
再加注异常,并且调用者需要检查它。所以这个包装并没有真正帮助。我会留下答案供参考,但正确的方法可能是@ShadowRanger's answer。
也许你可以在这里利用类继承:
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()
,但实际执行此操作的方式可能取决于您使用的框架(如果有)。