java支付宝退款 无效签名 手机网站支付签名无效求解答

支付宝ios支付请求Java服务端签名报的一个错(ALI40247) 原创
来源:博客园
今天做app的支付宝支付,遇到些问题,以前做支付宝支付签名都是直接在客户端App进行,今天下了最新版本ios的支付宝支付demo,运行demo时底部有红色的显眼字体,告知用户签名必须在服务端进行...原因当然是为了安全,不过我今天虽然将支付宝的ras签名放到了服务端,但是我这里得说一个问题, 红字提示的安全问题对ios来说应该不那么严重,对android来说应该危险性还是比较高的,因为客户端签名,私钥就必须放到客户端里。
接下去主要说说我今天遇到的问题,如果直接使用ios客户端签名无任何问题,可以直接支付,但是如果将需要签名的字符串通过接口请求传给java签名就会出一个问题,请求服务端签名时,我们可以直接将客户端的order转换成字符串传过去,这样在服务端就只需要调用一个签名方法即可,下面我来说下报的这个错--&ALI40247,网上找了关于这个错的原因, 对比了发现并不是这些原因导致的,之后发现是--&java的签名与objective-c的签名结果不一样,都是使用的相同的加密串官方demo签名方法,为什么出现签名不一样,最后发现虽然oc和java的签名结果不一样,但是有一个规律--&java中签名的"/"符号在oc签名中是用"%"号代替,然后java的rsa签名结果都有一个"=",但是在ios中这个"="等于 "%3D",开始我说了直接用ios 客户端签名是可以直接支付的,那么只要java返回的签名与ios一样就行了,虽然他们签名结果不一样,但是现在发现一个固定的规律,所以只需要将java服务端返回的签名中的特殊符号替换成ios签名中的特殊符号就行了。
免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动1:支付宝官方文档和demo,大家可以去下载学习 https://doc./docs/doc.htm?spm=a219a..0.agOMhi&treeId=60&articleId=103564&docType=1 我也是看文档,然后自己摸索查资料最后才搞定的,全程下来确实学到不少东西; 2:签名方式及语言版本选择 我的这个H5支付功能是嵌入到thinkphp框架里的,现以thinkphp框架来说明; demo里默认有两种签名方式,MD5和RSA,我选择的是MD5,每种签名方式里都有三种语言支持:C#,JAVA,PHP;我选择的是php
以上是目录结构;如果嵌入到thinkphp中需要做一些调整,以下详细说明 3:嵌入到thinkphp 嵌入到thinkphp,我将目录结构做了一些调整,将alipayapi.php,notify_url.php,return_url.php三个文件整合在了一起,放在Action目录下的AliPayAction.class.php文件里,其他的文件单独放在Org文件下,视图文件放在Tpl文件夹下的
具体文件的放置需要根据项目的实际情况来确定,我这里是我自己项目里的位置以作说明; 这个是配置文件的代码:
这个是AliPayAction.class代码,以下是支付的核心代码,
需要注意的是$parameter数组里的很多字段,会通过回调回传至回调方法里,以便与做后续处理, 同步回调
异步回调:可在异步回调方法里处理订单逻辑,例如异步回调成功之后,根据订单号查询订单信息,修改订单状态等;
视图文件代码:
最终在UC浏览器实现的效果:
4:开发过程中,有许多的细节需要注意,避免采坑,需要仔细看文档; 写的比较粗糙,大家见谅!
最新教程周点击榜
微信扫一扫最近在做android~,恩,就说这么多吧
1,准备工作
支付宝相关文档下载地址:
当然了,假设你已经有了pid(partner)和商户账户(seller),并且开通了手机网页支付功能。
下载的包里面,打开【手机网页即时到账接口】文件夹,看到里面的可以看看里面的pdf文档,【手机网页支付接入与使用规则.pdf】这个文档有教你怎么在支付宝开通相关的东西,这里我提一下,记得把公钥上传,然后私钥生成出来
这个包,对于android,虽然没有需要的lib,但是文档的相关参数说明也是必须的。
看文档,可以知道,网页支付需要两步,第一步是获取授权令牌,第二步根据这个令牌进行交易。
那么在第一步的时候,我们要根据文档提供的url获取令牌,这个时候我们要发起http请求,获得返回的内容,解析出来授权令牌,再去发请求,得到支付宝的支付网页,显示即可
我的做法是,第一步用http请求,第二步是webview加载链接
2,代码相关
假设你已经有了android工程,打开下载的包里面的demo【WS_WAP_PAYWAP-JAVA-UTF-8】在src目录下找到sign这个package然后把RSA.java拿出来,放到你的android工程里,因为我只用了RSA加密所以这里只拿了这一个,如果你需要其他加密方法,那就拿其他的……
还没完,再到util包里面打开AlipaySubmit.java类,找到:
* 解析远程模拟提交后返回的信息,获得token
* @param text 要解析的字符串
* @return 解析结果
* @throws Exception
public static String getRequestToken(String text) throws Exception {
String request_token = &&;
//以“&”字符切割字符串
String[] strSplitText = text.split(&&&);
//把切割后的字符串数组变成变量与数值组合的字典数组
Map&String, String& paraText = new HashMap&String, String&();
for (int i = 0; i & strSplitText. i++) {
//获得第一个=字符的位置
int nPos = strSplitText[i].indexOf(&=&);
//获得字符串长度
int nLen = strSplitText[i].length();
//获得变量名
String strKey = strSplitText[i].substring(0, nPos);
//获得数值
String strValue = strSplitText[i].substring(nPos+1,nLen);
//放入MAP类中
paraText.put(strKey, strValue);
if (paraText.get(&res_data&) != null) {
String res_data = paraText.get(&res_data&);
//解析加密部分字符串(RSA与MD5区别仅此一句)
if(AlipayConfig.sign_type.equals(&0001&)) {
res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
//token从res_data中解析出来(也就是说res_data中已经包含token的内容)
Document document = DocumentHelper.parseText(res_data);
request_token = document.selectSingleNode( &//direct_trade_create_res/request_token& ).getText();
return request_
这个方法拿出来,也放到RSA里面去,其中:
res_data = RSA.decrypt(res_data, AlipayConfig.private_key, AlipayConfig.input_charset);
&这一句中,private_key是生成的私钥转换成PKCS8的内容(如果你不知道怎么生成,请打开demo里面的openssl工程,里面有一个生成命令文档,按照里面的命令即可),不是直接的RSA私钥,input_charset换成utf-8即可,
Document document = DocumentHelper.parseText(res_data);
request_token = document.selectSingleNode( &//direct_trade_create_res/request_token& ).getText();
这两句,请换成成:
Log.d(&res_data&, res_data);
request_token = res_data.substring(res_data.indexOf(&&?&));
int startIndex = request_token.indexOf(&&request_token&&);
if (startIndex & -1) {
int temp = &&request_token&&.length();
String start = request_token.substring(temp+startIndex, temp+startIndex+22);
Log.d(&start&, start);
int endIndex = request_token.indexOf(&&/request_token&&);
String end = request_token.substring(endIndex - 18, endIndex);
Log.d(&end&, end);
return start+
Log.d(&request_token&, request_token);
这里说明一下为什么,首先它的这两句无非就是xml的解析,我们没必要这么用,还要加上它的包,另外,我发现解析出来的授权令牌里面有乱码,不管我怎么设置编码都有,本想联系客服问个原因,但是一直都是繁忙中,无奈我只能截取一下,先用着,望有知道的同学告知一下……
看我们的付款layout:
&RelativeLayout xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&match_parent&&
&RelativeLayout
android:id=&@+id/top_bar&
android:layout_width=&match_parent&
android:layout_height=&55dp&
android:layout_alignParentTop=&true&
android:background=&@color/light_black&
android:padding=&4dp&&
android:id=&@+id/back_btn&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_centerVertical=&true&
android:layout_marginLeft=&4dp
android:gravity=&center&
android:padding=&6dp&
android:text=&@string/home_back&
android:textColor=&@drawable/top_bar_selector&
android:textSize=&20sp& /&
android:id=&@+id/main_app_name&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_centerInParent=&true&
android:text=&支付宝网页版&
android:textColor=&@android:color/white&
android:textSize=&22sp& /&
&/RelativeLayout&
android:id=&@+id/webview&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:layout_below=&@+id/top_bar&
android:scrollbars=&none& /&
&/RelativeLayout&
其中的一些color,背景等大家自己调一下,这里面很简单就一个webview
在Activity里面初始化好相关内容,其中关于webview设置如下:
webView.getSettings().setJavaScriptEnabled(true);//允许webkit执行js代码;
webView.setWebChromeClient(new WebChromeClient() {
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
return super.onJsAlert(view, url, message, result);
webView.setWebChromeClient(new WebChromeClient() {
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return super.shouldOverrideUrlLoading(view, url);
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (progressDialog != null) {
progressDialog.dismiss();
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
其中有一个关闭progressdialog的步骤,这里面如果你没有这个东西,直接注释掉吧。
至此,在我们的oncreate初始话之后呢,加上我们的令牌获取请求,再此之前我们先要初始化一些参数,首先在我们的RSA.java里面添加几个方法:
订单(其中的userid如果没有可以去掉,成功后的页面和通知页面这个你要有自己的处理,当然目前没有的话也可以向我一样写上百度的地址……):
public static String getAliPayWAPOrderBodyInfor(String subject, String price, String refNo, String SUCCESS_URL, String NOTIFY_URL, String userid) {
String orderInfor = &&direct_trade_create_req&&su& +
&bject&& + subject +
&&/subject&&out_trade_no&& + &1& + &&/out_trade_no&&total_fee&& + price + &&/tot& +
&al_fee&&seller_account_name&& + AliPayUtil.SELLER + &&/seller_account_name&&call_& +
&back_url&& + SUCCESS_URL + &&/call_back_& +
&url&&notify_url&& + NOTIFY_URL + &&/notify_url&&out_user&& + userid + &&/out_user&&pay_expire&3600&/pay_expire&&/direct_trade_create& +
return orderI
授权令牌参数:
public static Map&String, String& getAccessTokenParamsMap() {
Map&String, String& sParaTemp = new HashMap&String, String&();
sParaTemp.put(&service&, &alipay.wap.trade.create.direct&);
sParaTemp.put(&partner&, AliPayUtil.PARTNER);//这里换成你的pid
sParaTemp.put(&sec_id&, &0001&);//这是RSA加密
sParaTemp.put(&format&, &xml&);
sParaTemp.put(&v&, &2.0&);
sParaTemp.put(&req_id&, UtilDate.getOrderNum());//这个方法可以把util包里面的这个UtilDate.java拿过来,当然了没必要的话直接把相关的方法拿过来
return sParaT
交易参数:
public static Map&String, String& getBillParamsMap() {
Map&String, String& sParaTemp = new HashMap&String, String&();
sParaTemp.put(&service&, &alipay.wap.auth.authAndExecute&);
sParaTemp.put(&partner&, AliPayUtil.PARTNER);//这里换成你的pid
sParaTemp.put(&sec_id&, &0001&);
sParaTemp.put(&format&, &xml&);
sParaTemp.put(&v&, &2.0&);
return sParaT
参数拼接方法(在util包的AlipayCore.java中)
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
public static String createLinkString(Map&String, String& params) {
List&String& keys = new ArrayList&String&(params.keySet());
Collections.sort(keys);
String prestr = &&;
for (int i = 0; i & keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + &=& +
prestr = prestr + key + &=& + value + &&&;
生成sign签名的方法 :
public static String buildRequestMysign(Map&String, String& sPara) {
String prestr = AlipayCore.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
String mysign = &&;
mysign = sign(prestr, private_key, &utf-8&);
然后再你的activity里面这样调用:
&pre name=&code& class=&html&&Map&String, String& sParaTemp = AliPayUtil.getAccessTokenParamsMap();
sParaTemp.put(&req_data&, RSA.getAliPayWAPOrderBodyInfor(SUBJECT, price, &1&, SUCCESS_URL, NOTIFY_URL, userid));
//生成签名结果
String mysign = RSA.buildRequestMysign(sParaTemp);
//签名结果与签名方式加入请求提交参数组中
sParaTemp.put(&sign&, mysign);
这样我们的参数map就做好了,当然了 一般我们是用post请求所以好要把它转化一下,像这样:
private List&NameValuePair& generatNameValuePair(Map&String, String& properties) {
List&NameValuePair& nameValuePair = new ArrayList&NameValuePair&(properties.size());
for (Map.Entry&String, String& entry : properties.entrySet()) {
nameValuePair.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
return nameValueP
这样你就可以以post形式发了,post的url是/service/rest.htm,参数是上面的list
因为我这边用了一些框架所以对于异步的请求,很好处理,但如果你没有用呢,无非就是handler,message机制,总之,假设你得到了正确的响应结果(不正确的话,看一下code值,和文档中比较一下,j看看是什么错误),然后对结果处理:
String dec = &&;
dec = URLDecoder.decode(result, &utf-8&);//请将result换成你的请求结果
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
ret = RSA.getRequestToken(dec);
Log.d(&ret&, ret);
if (ret!=null) {
wapPay(ret);
} catch (Exception e) {
e.printStackTrace();
先做一次urldecode,然后再解析数据:
其中的wapPay方法:
private void wapPay(String token) {
Map&String, String& sParaTemp = RSA.getBillParamsMap();
String req_data = &&auth_and_execute_req&&request_token&& + token + &&/request_token&&/auth_and_execute_req&&;
sParaTemp.put(&req_data&, req_data);
String mysign = RSA.buildRequestMysign(sParaTemp);
sParaTemp.put(&sign&, mysign);
List&NameValuePair& paramspost = generatNameValuePair(sParaTemp);
String url = &/service/rest.htm?& + URLEncodedUtils.format(paramspost, &UTF-8&);
webView.loadUrl(url);
好的至此,我们可以看到页面了:
后面的步骤大家就直接看着来把。支付宝新版支付接口Java后台签名_Java_第七城市
支付宝新版支付接口Java后台签名
一、APP支付支付宝更新了支付接口,同时也给出了服务端SDK供下载使用。该SDK提供了一系列的工具类和部分请求的实现。提供了一个AlipaySignature类来提供统一的签名工具类来帮助用户快速实现签名。在SDK下载的文档最后一个部分,提示用户在签名的时候使用String AlipaySignature.rsaSign(Map&String, String& params, String privateKey, String charset)这个方法来做签名。使用该SDK,首先需要构建一个AlipayClient,如果单纯只是使用了签名的功能,对AlipayClient这个对象的实例化并不是很必要。要注意的是,这边初始化的时候,要提供APP_PRIVATE_KEY和ALIPAY_PUBLIC_KEY,这两个需要明确一下。APP_PRIVATE_KEY是由使用支付宝支付的用户自己生成的RSA私钥,用户使用该私钥对串进行加密,支付宝使用用户提交给支付宝的对应公钥来校验是否合法的请求。而ALIPAY_PUBLIC_KEY是支付宝生成的RSA密钥中的公钥,支付宝保留自己私钥,在自己内部服务器中对请求加密,用户使用支付宝的公钥来校验请求是否合法,在支付宝支付的回调和请求的返回时都需要使用支付宝提供的公钥来校验。这其中查看应用公钥就是用户自己生成的公钥,查看支付宝公钥就是支付宝提供的公钥。要记住,用户端加密过程中,使用的都是用户自己的私钥,而在接收到支付宝的返回请求时验签使用的都是支付宝提供的公钥。加密的过程中,用户首先生成自己的请求Map数据,然后调用支付宝的rsaSign方法加密生成签名。之后需要按照申请支付请求参数说明中后部分所给出的方法对签名串和map中的数据组合成为一个字符串返回给客户端,客户端使用这个串来向支付宝发起支付。需要注意的是,rsaSign签名使用的map数据,需要在map中加入sign_type=RSA这个key-value对。而在校验从支付宝回调回来的请求验签时又不需要sign_type这个键值对。二、支付宝网页支付支付宝提供的SDK中,网页支付是默认就有一套请求的实现的,对应的请求类是AlipayTradeWapPayRequest,在设置完成参数之后,调用alipayClient.executePage,就能够完成支付页面的生成,这个在支付宝的手机网站支付快速接入中已经有完整的调用流程,这种方法是通过将跳转页面输出到页面中来实现的。
最新教程周点击榜
微信扫一扫Pages: 1/2
主题 : android机器调用anysdk支付宝时报签名错误,如何解决?
级别: 新手上路
可可豆: 49 CB
威望: 49 点
在线时间: 19(时)
发自: Web Page
来源于&&分类
android机器调用anysdk支付宝时报签名错误,如何解决?&&&
java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag调用支付宝时报这个错求解决。感激不尽。如图:
图片:QQ截图14.png
UID: 262363
发帖: 1043
可可豆: 2761 CB
威望: 2231 点
在线时间: 2677(时)
发自: Web Page
向开发人员反应这个问题了
级别: 新手上路
可可豆: 49 CB
威望: 49 点
在线时间: 19(时)
发自: Web Page
回 1楼(孤独の快乐) 的帖子
以前遇到时4.1.0以上版本有这个情况把KeyFactory keyf = KeyFactory.getInstance(&RSA&);改成:KeyFactory keyf = KeyFactory.getInstance(&RSA&, &BC&);就好了现在被anysdk封起来了,求速填此坑&& 或给我个开发人员的联系方式
UID: 262363
发帖: 1043
可可豆: 2761 CB
威望: 2231 点
在线时间: 2677(时)
发自: Web Page
对了,你privateKey和publicKey写反了没,参数错了也会出现这个错误 [ 此帖被孤独の快乐在 19:10重新编辑 ]
级别: 新手上路
可可豆: 49 CB
威望: 49 点
在线时间: 19(时)
发自: Web Page
回 3楼(孤独の快乐) 的帖子
没有反, 4.1以下的机器能正常调出来支付宝, 4.1以上的就不行了
UID: 262363
发帖: 1043
可可豆: 2761 CB
威望: 2231 点
在线时间: 2677(时)
发自: Web Page
Re:回 3楼(孤独の快乐) 的帖子
引用 引用第4楼yjypgf于 10:14发表的 回 3楼(孤独の快乐) 的帖子 : 没有反, 4.1以下的机器能正常调出来支付宝, 4.1以上的就不行了
你邮箱多少?我把修改的插件发给你试试
级别: 新手上路
可可豆: 49 CB
威望: 49 点
在线时间: 19(时)
发自: Web Page
回 5楼(孤独の快乐) 的帖子
UID: 262363
发帖: 1043
可可豆: 2761 CB
威望: 2231 点
在线时间: 2677(时)
发自: Web Page
Re:回 5楼(孤独の快乐) 的帖子
引用 引用第6楼yjypgf于 20:26发表的 回 5楼(孤独の快乐) 的帖子 :
已发,你试试可不可以
UID: 262363
发帖: 1043
可可豆: 2761 CB
威望: 2231 点
在线时间: 2677(时)
发自: Web Page
怎么样,可以用不?
级别: 新手上路
可可豆: 49 CB
威望: 49 点
在线时间: 19(时)
发自: Web Page
回 8楼(孤独の快乐) 的帖子
可以用了,&&不过, 这个插件, 我支付的钱怎么都是1元呢, 无论我传的价格是多少最后都变成付1元了
Pages: 1/2
关注本帖(如果有新回复会站内信通知您)
苹果公司现任CEO是谁?2字 正确答案:库克
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 浏览移动版

我要回帖

更多关于 支付宝 无效签名 的文章

 

随机推荐