python+Django原生 支付寶支付
阿新 • • 發佈:2019-01-24
views檢視處理
def AliPay(request): if request.is_secure(): notify_url = "https://%s/xxx/xxx/" % request.get_host() # 非同步通知 return_url = "https://%s/xxx/xxx/" % request.get_host() # 同步通知 else: notify_url = "http://%s/xxx/xxx/" % request.get_host() return_url = "http://%s/xxx/xxx/" % request.get_host() # 沙箱環境地址 alipay = AliPay( appid="", app_notify_url=notify_url, return_url=return_url, app_private_key_path="", alipay_public_key_path="", # 開啟檔案模式 """ app_private_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem"), alipay_public_key_path=os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem"), # 支付寶的公鑰,驗證支付寶回傳訊息使用,不是你自己的公鑰, """ ) data = request.GET money_key = data.get('money_key') total_key = data.get('total_key') query_params = alipay.direct_pay( subject=WEBSITE_CONF[request.get_host()]["website_name"], # 名 out_trade_no=total_key, # 商戶訂單號 total_amount=money_key, # 交易金額 return_url=return_url, ) alipay_url = "https://openapi.alipay.com/gateway.do?{0}".format(query_params) response = HttpResponse(json.dumps({"alipay_url": alipay_url})) return response
支付寶工具Utils
class AliPay(): """支付寶支付介面(PC端支付介面)""" # 初始化資訊 def __init__(self, appid, app_notify_url, app_private_key_path, alipay_public_key_path, return_url, debug=False): self.appid = appid # 開發者的應用 self.app_notify_url = app_notify_url self.app_private_key = RSA.importKey(app_private_key_path) # 公鑰 self.alipay_public_key = RSA.importKey(alipay_public_key_path) self.return_url = return_url # 返回的url # 使用檔案讀取模式開啟下面 """ self.app_private_key_path = app_private_key_path self.alipay_public_key_path = app_private_key_path with open(self.app_private_key_path) as fp: self.app_private_key = RSA.importKey(fp.read()) with open(self.alipay_public_key_path) as fp: self.alipay_public_key = RSA.importKey(fp.read()) """ if debug is True: self.__gateway = "https://openapi.alipaydev.com/gateway.do" else: self.__gateway = "https://openapi.alipay.com/gateway.do" def direct_pay(self, subject, out_trade_no, total_amount, return_url, **kwargs): biz_content = { "subject": subject, # 訂單標題 "out_trade_no": out_trade_no, # 商戶訂單號 "total_amount": total_amount, # 訂單金額 "product_code": "FAST_INSTANT_TRADE_PAY", # 快速即時貿易支付 'return_url': return_url # "qr_pay_mode":4 } biz_content.update(kwargs) data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url) return self.sign_data(data) def build_body(self, method, biz_content, return_url=None): data = { "app_id": self.appid, "method": method, "charset": "utf-8", "sign_type": "RSA2", "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "version": "1.0", "biz_content": biz_content } if return_url is not None: data["notify_url"] = self.app_notify_url data["return_url"] = self.return_url return data def sign_data(self, data): data.pop("sign", None) # 排序後的字串 unsigned_items = self.ordered_data(data) unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items) sign = self.sign(unsigned_string.encode("utf-8")) # ordered_items = self.ordered_data(data) quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items) # 獲得最終的訂單資訊字串 signed_string = quoted_string + "&sign=" + quote_plus(sign) return signed_string def ordered_data(self, data): complex_keys = [] for key, value in data.items(): if isinstance(value, dict): complex_keys.append(key) # 將字典型別的資料dump出來 for key in complex_keys: data[key] = json.dumps(data[key], separators=(',', ':')) return sorted([(k, v) for k, v in data.items()]) def sign(self, unsigned_string): # 開始計算簽名 key = self.app_private_key signer = PKCS1_v1_5.new(key) signature = signer.sign(SHA256.new(unsigned_string)) # base64 編碼,轉換為unicode表示並移除回車 sign = b64encode(signature).decode("utf8").replace("\n", "") return sign def _verify(self, raw_content, signature): # 開始計算簽名 key = self.alipay_public_key signer = PKCS1_v1_5.new(key) digest = SHA256.new() digest.update(raw_content.encode("utf8")) if signer.verify(digest, b64decode(signature.encode("utf8"))): return True return False def verify(self, data, signature): if "sign_type" in data: sign_type = data.pop("sign_type") # 排序後的字串 unsigned_items = self.ordered_data(data) message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items) return self._verify(message, signature)