you can refer to my implementation in python:
https://github.com/yiakwy/Siganture-Authentication-Package/blob/master/SDK/sign5py3k.py
in client side:
Request.py
(1) in Authorization part, it should start with "Signature" so that other programmes can know at which part of authorization process you are in.
(2) You did not specify which encoding algorithms you are using. This should be a serious bug in the future. Optionally, you should specify which headers you want to use to encode for a signature. 403 response will tell users how to use headers.
(3) signature template should be :
signature_string = "(request-target): {method} {path}\n{ret}" (notice to ascii space)
and path
should be included in signature_string template. The path
does not include parameters
otherwise for some url, the result of which will exceed 128 bytes.
config.py
the best practice should be:
a global_config.py for system. Then use dir
to open a user's local config
and replace the default values with ones defined by a user. I noticed that you use yaml. But in python, .py is just enough because it is a dynamic language. Using .py, you can implement "Lazy loading mode" very easily.
Architecture
As a SDK, I suggest the architecture as following:
Config & authentication
Global_config.py
Auth.py
- SignatureAuthentication(Authentication)
Qingstor.py
class QingstorAuthentication(SignatureAuthentication):
def __init__(app_key, app_secret, permi=(), timeout=60)
class Application:
def make_req(method, url, params, headers, timeout)
# use httpConnection, Reqeust, Oauth whatever method you like ,,, haha
class QingstorApplication(Application):
# business logics
def get_xx
def get_yy
def get_zz
-
Constants should be defined in __init__.py
; you can also import other files in __init__.py
-
Do to abuse to use get_xx
method, if you just want to get attribute internally , access it directly or use _get_xx
method instead.
error.py
- I suggest to define a
handle_error
method in "exception.py" or "error.py"
def handler_errors(func)
logger = loggerAdapter(_log, func.__name__)
def wrapper(*args, **kw):
try:
ret = func(*args, **kw)
except xx:
except yy:
except zz:
logger.WHAT[ex]()
# return None or raise an error as you wish
return wrapper