IOS端
引入官方库(于Podfile文件加入如下内容并运行 pod install)
pod 'AlipaySDK-iOS'
于头文件添加如下内容,不知道什么是头文件的建议参考支付宝IOS官方接入文档
#import
添加 URL Schemes ,设置为aliauth 并设置值为某一唯一值,如 包名.aliauth。设置为alipay 并设置值为某一唯一值,如 包名.alipay。
与Localizable.strings 添加 “aliauthback” = “”//这里需要保持与上面的URL Schemes aliauth值一致。添加 “alipayback” = “”//这里需要保持与上面的URL Schemes alipay值一致。
创建AliPayUtils工具文件
class AliPayUtils {
private static var aliAuthBack: AliPayBack?
private static var aliPayBack: AliPayBack?
static func login(signStr: String, aliAuthBack: AliPayBack?) {
AliPayUtils.aliAuthBack = aliAuthBack
AlipaySDK().auth_V2(withInfo: signStr, fromScheme: NSLocalizedString("aliauthback", comment: ""), callback: { (resp) in
loginBack(resultDic: resp as! [NSObject: AnyObject])
})
}
static func loginBack(resultDic: [NSObject: AnyObject]) {
if let Alipayjson: [String: AnyObject] = resultDic as? [String: AnyObject] {
let resultStatus = Alipayjson["resultStatus"] as! String
print("loginBack resultStatus=\(resultStatus)")
if resultStatus == "9000" {// 请求处理成功
aliAuthBack?.finish(Alipayjson["result"] as? String)
} else {
aliAuthBack?.failed()
}
}
}
static func pay(signStr: String, aliPayBack: AliPayBack?) {
AliPayUtils.aliPayBack = aliPayBack
AlipaySDK().payOrder(signStr, fromScheme: NSLocalizedString("alipayback", comment: ""), callback: { (resp) in
payBack(resultDic: resp as! [NSObject: AnyObject])
})
}
static func payBack(resultDic: [NSObject: AnyObject]) {
if let Alipayjson: [String: AnyObject] = resultDic as? [String: AnyObject] {
let resultStatus = Alipayjson["resultStatus"] as! String
print("payBack resultStatus=\(resultStatus)")
if resultStatus == "9000" || resultStatus == "8000" {// 订单支付成功或正在处理中
aliPayBack?.finish(Alipayjson["result"] as? String)
} else {
aliPayBack?.failed()
}
}
}
}
protocol AliPayBack {
func finish(_ result: String?)
func failed()
}
于AppDelegate添加回调(这里贴主要代码)
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, handleOpen url: URL) -> Bool {
switch url.scheme {
case NSLocalizedString("aliauthback", comment: ""):
AlipaySDK().processAuth_V2Result(url) { (back) in
AliPayUtils.loginBack(resultDic: back as! [NSObject: AnyObject])
}
case NSLocalizedString("alipayback", comment: ""):
AlipaySDK().processOrder(withPaymentResult: url) { (back) in
AliPayUtils.payBack(resultDic: back as! [NSObject: AnyObject])
}
default:
print("handleOpenUrl1")
}
print("handleOpenUrl11=\(url.scheme)")
return true
}
func application(_ application: UIApplication, open url: URL
, sourceApplication: String?, annotation: Any) -> Bool {
switch url.scheme {
case NSLocalizedString("aliauthback", comment: ""):
AlipaySDK().processAuth_V2Result(url) { (back) in
AliPayUtils.loginBack(resultDic: back as! [NSObject: AnyObject])
}
case NSLocalizedString("alipayback", comment: ""):
AlipaySDK().processOrder(withPaymentResult: url) { (back) in
AliPayUtils.payBack(resultDic: back as! [NSObject: AnyObject])
}
default:
print("handleOpenUrl2")
}
print("handleOpenUrl12=\(url.scheme)")
return true
}
}
登录调用(这里写部分伪代码):
//从服务器获取签名字符串,这里后面服务器开发会贴出,客户端可以不用管。
var signStr = getSignStrFromService()
AliPayUtils.login(signStr: result!, aliAuthBack: AliAuthBack())
//创建AliPayBack实例
struct AliAuthBack: AliPayBack {
func finish(_ result: String?) {
//登录成功,直接将获取的结果上传至服务器处理,服务器返回用户信息即可。
}
func failed() {
//登录失败
}
}
Android端
接入前奏,注册签约的可另行百度,这里主要写代码部分
下载jar包并导入(这里使用的是alipaySdk-20180601.jar)
放入项目libs文件夹下
与build.gradle导入jar(这里贴部分关键代码)
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation files('libs/alipaySdk-20180601.jar')
}
于AndroidManifest.xml注册权限及activity(这里贴出部分关键代码)
创建AliPayUtils工具文件(AuthResult/PayResult文件会后面贴出)
import android.app.Activity;
import android.text.TextUtils;
import android.util.Log;
import com.alipay.sdk.app.AuthTask;
import com.alipay.sdk.app.EnvUtils;
import com.alipay.sdk.app.PayTask;
import java.util.Map;
public class AliPayUtils {
public interface Back {
public void success(String result);
public void failed();
}
public static void startPay(final Activity activity, final String orderInfo, final Back back) {
if (orderInfo == null || back == null) {
return;
}
new Thread(new Runnable() {
@Override
public void run() {
// EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);//测试使用此设置
EnvUtils.setEnv(EnvUtils.EnvEnum.ONLINE);//正式环境使用此设置
PayTask alipay = new PayTask(activity);
Map result = alipay.payV2(orderInfo, true);
PayResult payResult = new PayResult(result);
String resultStatus = payResult.getResultStatus();
if (TextUtils.equals(resultStatus, "9000")) {
back.success(payResult.getResult());
} else {
back.failed();
}
}
}).start();
}
public static void login(final Activity activity, final String authInfo, final Back back) {
if (authInfo == null || back == null) {
return;
}
new Thread(new Runnable() {
@Override
public void run() {
AuthTask authTask = new AuthTask(activity);
Map result = authTask.authV2(authInfo, true);
AuthResult authResult = new AuthResult(result, true);
String resultStatus = authResult.getResultStatus();
if (TextUtils.equals(resultStatus, "9000")
&& TextUtils.equals(authResult.getResultCode(), "200")) {
back.success(authResult.getResult());
} else {
back.failed();
}
}
}).start();
}
}
创建AuthResult工具文件
import android.text.TextUtils;
import java.util.Map;
public class AuthResult {
private String resultStatus;
private String result;
private String memo;
private String resultCode;
private String authCode;
private String alipayOpenId;
public AuthResult(Map rawResult, boolean removeBrackets) {
if (rawResult == null) {
return;
}
for (String key : rawResult.keySet()) {
if (TextUtils.equals(key, "resultStatus")) {
resultStatus = rawResult.get(key);
} else if (TextUtils.equals(key, "result")) {
result = rawResult.get(key);
} else if (TextUtils.equals(key, "memo")) {
memo = rawResult.get(key);
}
}
String[] resultValue = result.split("&");
for (String value : resultValue) {
if (value.startsWith("alipay_open_id")) {
alipayOpenId = removeBrackets(getValue("alipay_open_id=", value), removeBrackets);
continue;
}
if (value.startsWith("auth_code")) {
authCode = removeBrackets(getValue("auth_code=", value), removeBrackets);
continue;
}
if (value.startsWith("result_code")) {
resultCode = removeBrackets(getValue("result_code=", value), removeBrackets);
continue;
}
}
}
private String removeBrackets(String str, boolean remove) {
if (remove) {
if (!TextUtils.isEmpty(str)) {
if (str.startsWith("\"")) {
str = str.replaceFirst("\"", "");
}
if (str.endsWith("\"")) {
str = str.substring(0, str.length() - 1);
}
}
}
return str;
}
@Override
public String toString() {
return "resultStatus={" + resultStatus + "};memo={" + memo + "};result={" + result + "}";
}
private String getValue(String header, String data) {
return data.substring(header.length(), data.length());
}
/**
* @return the resultStatus
*/
public String getResultStatus() {
return resultStatus;
}
/**
* @return the memo
*/
public String getMemo() {
return memo;
}
/**
* @return the result
*/
public String getResult() {
return result;
}
/**
* @return the resultCode
*/
public String getResultCode() {
return resultCode;
}
/**
* @return the authCode
*/
public String getAuthCode() {
return authCode;
}
/**
* @return the alipayOpenId
*/
public String getAlipayOpenId() {
return alipayOpenId;
}
}
创建PayResult工具文件
import android.text.TextUtils;
import java.util.Map;
public class PayResult {
private String resultStatus;
private String result;
private String memo;
public PayResult(Map rawResult) {
if (rawResult == null) {
return;
}
for (String key : rawResult.keySet()) {
if (TextUtils.equals(key, "resultStatus")) {
resultStatus = rawResult.get(key);
} else if (TextUtils.equals(key, "result")) {
result = rawResult.get(key);
} else if (TextUtils.equals(key, "memo")) {
memo = rawResult.get(key);
}
}
}
@Override
public String toString() {
return "resultStatus={" + resultStatus + "};memo={" + memo
+ "};result={" + result + "}";
}
/**
* @return the resultStatus
*/
public String getResultStatus() {
return resultStatus;
}
/**
* @return the memo
*/
public String getMemo() {
return memo;
}
/**
* @return the result
*/
public String getResult() {
return result;
}
}
AliPayUtils登录使用方式:
//于服务器获取登录签名字符串(这里为伪代码),具体代码后面服务器先关会贴出。
String signStr = getSignStr();
//调用AliPayUtils登录方法
AliPayUtils.login(DemoActivity.this, signStr, new AliPayUtils.Back() {
@Override
public void success(String result) {
//登录成功,可将result上传至服务器处理。
}
@Override
public void failed() {
//登录失败
}
});
服务器端
客户端的签名代码用的是客户端jar包,服务器端用的服务器jar包,且服务器根本没有签名示例代码。
为此楼主只有强行将客户端部分代码照搬至服务器端,不管是否规范,至少签名在服务器这边处理是做到了。代码如下(代码真心多,但是为了一个类完成所有功能,只能勉强放一起了。):
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;
public class AliPayUtils {
private static final String APP_ID = "";//这个就不强调了,这个都找不到相比开发难度很大,我这文笔很难帮到你了。
private static final String PID = "";//在开放平台内点击右上角那里点击密钥管理,然后点击左边mapi网关产品密钥就能看到pid了。
private static final String APP_PRIVATE_KEY = "";//下面的这些信息在应用信息里边基本能看到,有些可能需要上传设置。
private static final String RSA2_PRIVATE = "";//rsa2私钥
private static final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzG+wSFicJ1BAP+/51vY8Zn4ZVNMgWuJCTAvfUh48QjixfJwYdr0lX8aOOHVLiC4zOBMdKi0Ale/R/myl1duCnWhCz9XgxMG/x5MpuxESU0SY6HZimW wQGxoRmKsM3ICa7zmBa58nOig0cKY1ipJ6VXmTGSeiwF7TReKAGU8PeyYTZvnTgmIKofD7L8oAQF2xom3RlFbtzkjf4UaYbr+7m52dktPp6t7PwVKbbAiqDfVIoswrBaAPDmBWrf1Uaj8kt3KVzsiJzpN1xT0oRFikKj9KuMbIMI+ESpDr1674ToJa46AjI+0O8WxfQrebMuE/ xkUCG0WaQCXllLjtRXc7wIDAQAB";
private static final String CHARSET = "UTF-8";
public static boolean alipayCallBack(Map requestParams) {
Boolean isPay = false;
// 获取支付宝POST过来反馈信息
Map params = new HashMap<>();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
try {
boolean flag = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, "RSA2");
if (flag) {
String tradeStatus = params.get("trade_status");
if ("TRADE_SUCCESS".equals(tradeStatus)
|| "TRADE_FINISHED".equals(tradeStatus)) {
String outTradeNo = params.get("out_trade_no");// 商户订单号
String tradeNo = params.get("trade_no");// 商户订单号
String gmtPayment = params.get("gmt_payment");// 支付时间
String gmtCreate = params.get("gmt_create");// 创建时间
}
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return false;
}
public static AlipayTradeQueryResponse getPayInfo(String outTradeNo, String tradeNo) {
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do"
, APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"" + outTradeNo + "\"," +
"\"trade_no\":\"" + tradeNo + "\"," +
"\"org_pid\":\"" + PID + "\"" +
" }");
try {
return alipayClient.execute(request);
} catch (AlipayApiException e) {
return null;
}
}
public static String getPayStr(String totalAmount, String subject, String outTradeNo) {
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do"
, APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2");
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject(subject);
model.setOutTradeNo(outTradeNo);
model.setTimeoutExpress("10m");
model.setTotalAmount(totalAmount);
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("");//这里记得放支付回调地址
try {
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (response.isSuccess()) {
return response.getBody();
} else {
throw new BaseException(BaseResultEnum.ALIPAY_SIGN_ERROR);
}
} catch (AlipayApiException e) {
throw new BaseException(BaseResultEnum.ALIPAY_SIGN_ERROR);
}
}
public static AlipayUserInfoShareResponse signAuthStr(String authCode) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do", APP_ID
, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY
, "RSA2");
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(authCode);
AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest();
AlipaySystemOauthTokenResponse response =
alipayClient.execute(request);
if (response.isSuccess()) {
AlipayUserInfoShareResponse userInfoResponse
= alipayClient.execute(userInfoRequest, response.getAccessToken());
if (userInfoResponse.isSuccess()) {
return userInfoResponse;
}
System.out.println("signAuthStr调用成功");
} else {
System.out.println("signAuthStr 调用失败");
}
return null;
}
public static String getAuthStr() {
Map authInfoMap = buildAuthInfoMap();
String info = buildOrderParam(authInfoMap);
String sign = getSign(authInfoMap, RSA2_PRIVATE, true);
return info + "&" + sign;
}
private static String buildOrderParam(Map map) {
List keys = new ArrayList(map.keySet());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = map.get(key);
sb.append(buildKeyValue(key, value, true));
sb.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey);
sb.append(buildKeyValue(tailKey, tailValue, true));
return sb.toString();
}
private static Map buildAuthInfoMap() {
Map keyValues = new HashMap();
keyValues.put("app_id", APP_ID);
keyValues.put("pid", PID);
keyValues.put("apiname", "com.alipay.account.auth");
keyValues.put("app_name", "mc");
keyValues.put("biz_type", "openservice");
keyValues.put("product_id", "APP_FAST_LOGIN");
keyValues.put("scope", "kuaijie");
keyValues.put("target_id", String.valueOf(System.currentTimeMillis())
+ new Random().nextInt(10000));
keyValues.put("auth_type", "AUTHACCOUNT");
keyValues.put("sign_type", "RSA2");
return keyValues;
}
private static String getSign(Map map, String rsaKey
, boolean rsa2) {
List keys = new ArrayList(map.keySet());
Collections.sort(keys);
StringBuilder authInfo = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = map.get(key);
authInfo.append(buildKeyValue(key, value, false));
authInfo.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey);
authInfo.append(buildKeyValue(tailKey, tailValue, false));
String oriSign = sign(authInfo.toString(), rsaKey, rsa2);
String encodedSign = "";
try {
encodedSign = URLEncoder.encode(oriSign, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "sign=" + encodedSign;
}
private static String buildKeyValue(String key, String value, boolean isEncode) {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append("=");
if (isEncode) {
try {
sb.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
sb.append(value);
}
} else {
sb.append(value);
}
return sb.toString();
}
private static final String ALGORITHM = "RSA";
private static final String SIGN_ALGORITHMS = "SHA1WithRSA";
private static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";
private static final String DEFAULT_CHARSET = "UTF-8";
private static String getAlgorithms(boolean rsa2) {
return rsa2 ? SIGN_SHA256RSA_ALGORITHMS : SIGN_ALGORITHMS;
}
private static String sign(String content, String privateKey, boolean rsa2) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.getDecoder().decode(privateKey));
Security.addProvider(
new org.bouncycastle.jce.provider.BouncyCastleProvider());
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM, "BC");
PrivateKey priKey = keyFactory.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature
.getInstance(getAlgorithms(rsa2));
signature.initSign(priKey);
signature.update(content.getBytes(DEFAULT_CHARSET));
byte[] signed = signature.sign();
return Base64.getEncoder().encodeToString(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
贴完代码可能会有人代码报错,很正常,因为里边用到了官方没有说的代码(原始代码用的Android的jdk没问题,但是服务器端的部分jdk代码和客户端有差异,所以就报错了),解决方案:
# gradle用户在build.gardle加入:
"org.bouncycastle:bcprov-jdk16:1.45",
# mvn用户在pom.xml加入:
org.bouncycastle
bcprov-jdk16
1.45
这样服务器端签名代码就写好(只是签名字符串),调用getAuthStr()方法就能返回了。
首先将获得的realResult上传至服务器。然后我这边贴下服务器端的处理代码(首先是getAlipayAuthCode()方法,传入的是realResult,返回的是authCode,让后将获得的authCode传入signAuthStr()方法就获得了用户信息了,具体的信息可以参考官方文档):
private final String ALIPAY_AUTH_CODE_START = "auth_code=";
private final String ALIPAY_AUTH_CODE_END = "&";
private String getAlipayAuthCode(String response) {
String result = response.substring(response.indexOf(ALIPAY_AUTH_CODE_START)
+ ALIPAY_AUTH_CODE_START.length(), response.length() - 1);
return result.substring(0, result.indexOf(ALIPAY_AUTH_CODE_END));
}
public static AlipayUserInfoShareResponse signAuthStr(String authCode) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do", APP_ID
, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY
, "RSA2");
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(authCode);
AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest();
AlipaySystemOauthTokenResponse response =
alipayClient.execute(request);
if (response.isSuccess()) {
AlipayUserInfoShareResponse userInfoResponse
= alipayClient.execute(userInfoRequest, response.getAccessToken());
if (userInfoResponse.isSuccess()) {
return userInfoResponse;
}
System.out.println("signAuthStr调用成功");
} else {
System.out.println("signAuthStr 调用失败");
}
return null;
}
获得了支付宝用户信息整个登录流程也基本结束了,剩下的就是自己业务逻辑的处理了,因为整个流程实在太复杂,写的可能有很多不详细的地方,还望谅解,发现不对的地方还望及时指正,有问题也可以评论指出。