貌似好久没写文章了,今天来记录下最近用支付宝SDK获取芝麻信用分数的过程,以及踩过的坑。
个人感觉接芝麻信用分数时还是很简单的,基本都是服务端的任务,我们这边只需要将从支付宝授权获取的auth_code传给服务端,剩下的就是服务器的事了。但是还是有些小坑需要记录。
如果以后需要做支付宝登陆的,可以看这里,还是很详细的
Android 集成支付宝第三方登录
其实看官方的Demo也是很好的
踩坑一
当我把官方Demo下下来,配好APPID,PID,RSA2_PRIVATE之后,直接运行Demo直接蹦了,我就懵了,官方Demo居然会有问题,好吧,通过调试,定位是空指针
String oriSign = SignUtils.sign(authInfo.toString(), rsaKey, rsa2);
这里返回了null,无语了,通过网上查找问题,需要对其中封装好的方法修改
public static String sign(String content, String privateKey, boolean rsa2) {
try {
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(
Base64.decode(privateKey));
//后面需要下个"BC"参数
KeyFactory keyf = KeyFactory.getInstance(ALGORITHM, "BC");
PrivateKey priKey = keyf.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.encode(signed);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
修改之后就不会返回null。
然后就可以通过将签名之后的参数传给AuthTask的authV2授权,授权成功之后就可以获取auth_code,然后传给服务器。
踩坑二
我从支付宝获取的auth_code传给服务器,服务器居然不能用,好吧,尴尬的我本来想去问支付宝技术人员的,但是后台人员说可以修改scope的value为auth_zhima,当我修改之后居然真的成功了,好吧,支付宝文档上居然没有记录,这文档真心烂。。。。
public static Map<String, String> buildAuthInfoMap(String pid, String app_id, String target_id, boolean rsa2) {
Map<String, String> keyValues = new HashMap<String, String>();
// 商户签约拿到的app_id,如:2013081700024223
keyValues.put("app_id", app_id);
// 商户签约拿到的pid,如:2088102123816631
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", "auth_zhima");
// 商户唯一标识,如:kkkkk091125
keyValues.put("target_id", target_id);
// 授权类型, 固定值
keyValues.put("auth_type", "AUTHACCOUNT");
// 签名类型
keyValues.put("sign_type", rsa2 ? "RSA2" : "RSA");
return keyValues;
}
注意:支付宝的芝麻信用分数获取和支付公用的一套SDK,并且授权用到的sign,需要从服务器获取,如果直接在客户端生成那是不安全的。
获取分数的部分代码
public class ZhiMaUtil {
private static final int SDK_AUTH_Cacel = -1;
private static final int SDK_AUTH_Fail = 0;
private static final int SDK_AUTH_Success = 1;
private Context mContext;
private Callback mCallback;
private String token;
public ZhiMaUtil(Context context){
this.mContext = context;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_AUTH_Cacel: {
mCallback.getScoreFailed("用户取消授权");
break;
}
case SDK_AUTH_Fail: {
mCallback.getScoreFailed("授权失败");
break;
}
case SDK_AUTH_Success:{
AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true);
getMineService().getZmScore(token, authResult.getAuthCode()).enqueue(new retrofit2.Callback<BaseBean>() {
@Override
public void onResponse(Call<BaseBean> call, Response<BaseBean> response) {
if(response.isSuccessful()&&response.body() != null){
BaseBean baseBean = response.body();
mCallback.getScoreSuccess(baseBean.getData(), "获取分数成功");
}
}
@Override
public void onFailure(Call<BaseBean> call, Throwable t) {
mCallback.getScoreFailed("获取分数失败");
circleProgressDialog.dismiss();
}
});
}
default:
break;
}
}
};
public void zhiMaAuthTask(Callback callback){
if(callback == null){
throw new RuntimeException("callback can not null!!");
}
mCallback = callback;
token = "Bearer "+Preferences.getInstance().getAccessToken(mContext);
getMineService().getAuthSign(token).enqueue(new retrofit2.Callback<BaseBean>() {
@Override
public void onResponse(Call<BaseBean> call, final Response<BaseBean> response) {
if(response.isSuccessful()&&response.body().getErrcode() == 0&&response.body()!=null){
BaseBean body = response.body();
Map<String, String> authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap("你的pid", "你的app_id", String.valueOf(System.currentTimeMillis()), true);
String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);
final String authInfo = info + "&" + body.getData();
Runnable authRunnable = new Runnable() {
@Override
public void run() {
AuthTask authTask = new AuthTask((Activity) mContext);
// 调用授权接口,获取授权结果
Map<String, String> 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")){
Message msg = new Message();
msg.obj = result;
msg.what = SDK_AUTH_Success;
mHandler.sendMessage(msg);
}else if(TextUtils.equals(resultStatus, "6001")){
Message msg = new Message();
msg.what = SDK_AUTH_Cacel;
mHandler.sendMessage(msg);
}else {
Message msg = new Message();
msg.what = SDK_AUTH_Fail;
mHandler.sendMessage(msg);
}
}
};
// 必须异步调用
Thread authThread = new Thread(authRunnable);
authThread.start();
}else if(response.body() != null){
LljApplication.showToastShort(response.body().getErrmsg());
}
}
@Override
public void onFailure(Call<BaseBean> call, Throwable t) {
mCallback.getScoreFailed("获取分数失败");
}
});
}
public interface Callback{
void getScoreSuccess(String score, String msg);
void getScoreFailed(String msg);
}
我们需要拷贝Demo里面的AuthResult,Base64,OrderInfoUtil2_0,SignUtils四个封装好的类。
上面代码是个工具类,功能还是很简单的,主要步骤如下:
1.获取服务器的sign,拼接客户端生成的info
2.通过拼接的参数,调用支付宝的SDK授权处理
3.获取auth_code,传给服务器获取分数
4.成功之后通过回调,传给ui显示
OK,芝麻信用分数获取成功。