一、数据加密
1、两种加密算法
对称加密算法代表:DES、AES1.1 对称加密算法
堆成加密算法需要使用秘钥,加密时同时使用秘钥和加密算法进行加密,解密时再使用同一个秘钥来解密
1.2 非对称加密算法
非对称加密算法代表:RSA非对称加密算法在使用时也是使用秘钥加密,但是在解密时使用的的另一个秘钥,如果加密使用公钥,解密的则使用私钥,如果加密使用私钥,则解密时使用公钥
2、移动支付使用的加密算法
在做支付时使用 非对称加密算法。为防止黑客伪造客户端或者服务端,客户端和服务器端需要进行双向认证,因此同时会有两对公钥和私钥存在,一对是客户端的,另一对是服务器的。客户端的公钥自己保存,私钥给服务器,发送数据时使用公钥加密,服务器接收后使用私钥解密。服务器端的公钥自己保存,私钥给客户端,发送数据时使用公钥加密,客户端接收到后使用私钥解密。
二、支付宝SDK接入
1、创建应用
1.1 准备工作:营业执照影印件、法人身份证影印件,如果是代理人还需要代理人身份证影印件和委托书1.2 注册企业账户,注册完成后需要大约一直两天时间认证企业1.3 登录 ==> 管理中心==>创建应用(输入应用名称)==>选择功能信息添加功能==>点击上线==>输入相关信息1.4 创建完成后进入管理中心,找到创建的应用点击查看,选择应用环境来设置接口加签方式1.5 进入账户和秘钥管理设置合作伙伴密钥,设置RSA密钥,此处的密钥与1.4步骤中的密钥相同,设置完成后应用就创建完成了2、代码实现
public class PayDemoActivity extends FragmentActivity {
/**
* 注意:以下信息需要自己填入,一般写在服务端
*/
// 商户PID
public static final String PARTNER = "";
// 商户收款账号
public static final String SELLER = "";
// 商户私钥,pkcs8格式
public static final String RSA_PRIVATE = "";
// 支付宝公钥
public static final String RSA_PUBLIC = "";
private static final int SDK_PAY_FLAG = 1;
/**
* 接收支付结果信息并在客户端反馈
*/
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_PAY_FLAG: {
PayResult payResult = new PayResult((String) msg.obj);
/**
* 同步返回的结果必须放置到服务端进行验证(验证的规则请看https://doc.open.alipay.com/doc2/
* detail.htm?spm=0.0.0.0.xdvAU6&treeId=59&articleId=103665&
* docType=1) 建议商户依赖异步通知
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为“9000”则代表支付成功,具体状态码代表含义可参考接口文档
if (TextUtils.equals(resultStatus, "9000")) {
Toast.makeText(PayDemoActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
} else {
// 判断resultStatus 为非"9000"则代表可能支付失败
// "8000"代表支付结果因为支付渠道原因或者系统原因还在等待支付结果确认,最终交易是否成功以服务端异步通知为准(小概率状态)
if (TextUtils.equals(resultStatus, "8000")) {
Toast.makeText(PayDemoActivity.this, "支付结果确认中", Toast.LENGTH_SHORT).show();
} else {
// 其他值就可以判断为支付失败,包括用户主动取消支付,或者系统返回的错误
Toast.makeText(PayDemoActivity.this, "支付失败", Toast.LENGTH_SHORT).show();
}
}
break;
}
default:
break;
}
}
;
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pay_main);
}
/**
* Android原生页面中调用SDK支付
*/
public void pay(View v) {
// 获取商品信息
String orderInfo = getOrderInfo("测试的商品", "该测试商品的详细描述", "0.01");
/**
* 特别注意,这里的签名逻辑需要放在服务端,切勿将私钥泄露在代码中!
*/
String sign = sign(orderInfo);
try {
/**
* 仅需对sign 做URL编码
*/
sign = URLEncoder.encode(sign, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
/**
* 生成完整的符合支付宝参数规范的订单信息,一般回见获取orderInfo、sign和getSignType()
* 的代码放到服务端,客户端直接将getOrderInfo()方法中的所需的参数发送给服务端,有服务端直接返回完整的payInfo
*/
final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();
// 发出支付请求并获取到支付结果发送给Handler
Runnable payRunnable = new Runnable() {
@Override
public void run() {
// 构造PayTask 对象
PayTask alipay = new PayTask(PayDemoActivity.this);
// 调用支付接口,获取支付结果
String result = alipay.pay(payInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
/**
* get the sdk version. 获取SDK版本号
*/
public void getSDKVersion() {
PayTask payTask = new PayTask(this);
String version = payTask.getVersion();
Toast.makeText(this, version, Toast.LENGTH_SHORT).show();
}
/**
* 原生的H5(手机网页版支付切natvie支付) 【对应页面网页支付按钮】
*
* @param v
*/
public void h5Pay(View v) {
Intent intent = new Intent(this, H5PayDemoActivity.class);
Bundle extras = new Bundle();
/**
* url是测试的网站,在app内部打开页面是基于webview打开的,demo中的webview是H5PayDemoActivity,
* demo中拦截url进行支付的逻辑是在H5PayDemoActivity中shouldOverrideUrlLoading方法实现,
* 商户可以根据自己的需求来实现
*/
String url = "http://m.taobao.com";
// url可以是一号店或者淘宝等第三方的购物wap站点,在该网站的支付过程中,支付宝sdk完成拦截支付
extras.putString("url", url);
intent.putExtras(extras);
startActivity(intent);
}
/**
* 创建订单信息
* 注意:一般与sign()和getSignType()一起放到服务端,客户端直接将三个参数发送到服务端返回得到完整的 payInfo
*/
private String getOrderInfo(String subject, String body, String price) {
// 签约合作者身份ID
String orderInfo = "partner=" + "\"" + PARTNER + "\"";
// 签约卖家支付宝账号
orderInfo += "&seller_id=" + "\"" + SELLER + "\"";
// 商户网站唯一订单号
orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";
// 商品名称
orderInfo += "&subject=" + "\"" + subject + "\"";
// 商品详情
orderInfo += "&body=" + "\"" + body + "\"";
// 商品金额
orderInfo += "&total_fee=" + "\"" + price + "\"";
// 服务器异步通知页面路径
orderInfo += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
// 服务接口名称, 固定值
orderInfo += "&service=\"mobile.securitypay.pay\"";
// 支付类型, 固定值
orderInfo += "&payment_type=\"1\"";
// 参数编码, 固定值
orderInfo += "&_input_charset=\"utf-8\"";
// 设置未付款交易的超时时间
// 默认30分钟,一旦超时,该笔交易就会自动被关闭。
// 取值范围:1m~15d。
// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
// 该参数数值不接受小数点,如1.5h,可转换为90m。
orderInfo += "&it_b_pay=\"30m\"";
// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
orderInfo += "&return_url=\"m.alipay.com\"";
return orderInfo;
}
/**
* get the out_trade_no for an order. 生成商户订单号,该值在商户端应保持唯一(可自定义格式规范)
*/
private String getOutTradeNo() {
SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss", Locale.getDefault());
Date date = new Date();
String key = format.format(date);
Random r = new Random();
key = key + r.nextInt();
key = key.substring(0, 15);
return key;
}
/**
* 对订单信息进行签名
*
* @param content 待签名订单信息
*/
private String sign(String content) {
return SignUtils.sign(content, RSA_PRIVATE);
}
/**
* get the sign type we use. 获取签名方式
*/
private String getSignType() {
return "sign_type=\"RSA\"";
}
}
代码中所需的类通过导入jar包和拷贝支付宝Demo中的类获得
总结一下代码中的注释,客户端需要做的工作只有一下几点:1、在开放平台创建应用,将得到的商户PID、商户私钥,pkcs8格、支付宝公钥 给服务端开发人员, 订单信息的拼接、获取到sign和getSignType()都交给服务端去做。2、将代码中getOrderInfo中需要的参数发送给服务,然后获取到返回的完整支付信息,也就是代码中的payInfo3、调用支付宝支付接口进行支付并获取到支付结果4、根据支付结果展示支付的当前状态具体实现细节与服务端开发人员一起商量