蚂蚁开放平台开发第三方授权登陆(三):Android端

 

开发前提:

拥有支付宝账户登录授权业务入参pid值。拥有APPID、App支付宝登录功能并成功签约

一、需求

用户在APP点击登录后,选择第三方登录中的“支付宝”,跳转到支付宝客户端进行授权登录(手机安装了支付宝客户端),或网页端扫码登录(手机未安装支付宝客户端)。用户同意登录后获取到用户的基本信息。

 

二、开发流程

APP支付宝授权登录获取用户信息流程图:

蚂蚁开放平台开发第三方授权登陆(三):Android端_第1张图片

1.     Android客户端调用支付宝无线账户授权接口,引导用户授权,获取会员授权码(auth_code)与支付宝会员ID(user_id)。若匹配user_id成功,则完成登录;否则继续下一步。

2.     服务端调用授权令牌接口(alipay.system.oauth.token),通过auth_code换取access_token。auth_code作为换取access_token的票据,auth_code只能使用一次,一天未被使用自动过期。

3.     服务端调用用户信息共享接口(alipay.user.info.share),通过access_token获取用户的userId、昵称、头像等基础信息。access_token只能使用一次

 

三、开发环境及使用到的技术

1、后端采用IDEA2017 进行开发

2、前端使用Android Studio 3.1.3 进行开发

3、后端必须基于JDK7以上版本,采用JDK8开发,前端基于Android SDK4.4

4、使用fastJson对json数据进行处理

 

四、具体实现步骤

1.前端(Android)

目录结构

蚂蚁开放平台开发第三方授权登陆(三):Android端_第2张图片

1).Android微信授权登录开发环境配置

I.添加支付宝sdk包

将alipaySdk-xxxxxxxx.jar包放入应用工程的libs目录下。

蚂蚁开放平台开发第三方授权登陆(三):Android端_第3张图片

将jar包添加入环境,将libs目录下jar包导入。

Build.gradle中,导入包

dependencies {

// 支付宝相关

implementation files('libs/alipaySdk-20180601.jar')

}

II.修改Manifest文件

添加声明:









添加权限声明:

 

III.添加混淆规则:

在proguard-rules.pro文件中添加相关规则:

-keep class com.alipay.android.app.IAlixPay{*;}

-keep class com.alipay.android.app.IAlixPay$Stub{*;}

-keep class com.alipay.android.app.IRemoteServiceCallback{*;}

-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}

-keep class com.alipay.sdk.app.PayTask{ public *;}

-keep class com.alipay.sdk.app.AuthTask{ public *;}

-keep class com.alipay.sdk.app.H5PayCallback {

    ;

    ;

}

-keep class com.alipay.android.phone.mrpc.core.** { *; }

-keep class com.alipay.apmobilesecuritysdk.** { *; }

-keep class com.alipay.mobile.framework.service.annotation.** { *; }

-keep class com.alipay.mobilesecuritysdk.face.** { *; }

-keep class com.alipay.tscenter.biz.rpc.** { *; }

-keep class org.json.alipay.** { *; }

-keep class com.alipay.tscenter.** { *; }

-keep class com.ta.utdid2.** { *;}

-keep class com.ut.device.** { *;}

 

 

2).引导用户点击的按钮

新建login.xml.添加按钮

        

        

当用户点击后,会调用authV2方法

3).loginActivity.java

public class AliPayLoginActivity extends FragmentActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login);
}

I.相关配置参数:

private static final int SDK_PAY_FLAG = 1;
private static final int SDK_AUTH_FLAG = 2;

II.auth2方法

商户重要信息需要存放在服务端。

Auth2方法中需要做的就是请求我方服务端获取参数,根据参数请求蚂蚁金服开放平台服务端。

    public void authV2(View v) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                final String authInfo = ApacheHttpUtil.get("http://exzg5x.natappfree.cc"+"/alipay/sign/android");
                Runnable authRunnable = new Runnable() {
                    @Override
                    public void run() {
                        // 构造AuthTask 对象
                        AuthTask authTask = new AuthTask(AliPayLoginActivity.this);
                        // 调用授权接口,获取授权结果
                        Map result = authTask.authV2(authInfo, true);
                        Message msg = new Message();
                        msg.what = SDK_AUTH_FLAG;   //
                        msg.obj = result;
                        mHandler.sendMessage(msg);  // 请求成功后将会发送消息到handler处理
                    }
                };
                // 必须异步调用
                Thread authThread = new Thread(authRunnable);
                authThread.start();
            }
        }).start();
    }

III.Handler属性

如果获取到SDK_AUTH_FLAG消息,判断状态码成功后,表明授权成功,蚂蚁金服开放平台将会返回code和openid,根据这两个参数向服务端发送请求,获取用户信息。

根据请求获取到的数据进行解析处理,然后跳转到个人信息页。

@SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @SuppressWarnings("unused")
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SDK_AUTH_FLAG: {
                    @SuppressWarnings("unchecked")
                    final AuthResult authResult = new AuthResult((Map) msg.obj, true);
                    String resultStatus = authResult.getResultStatus();
                    // 判断resultStatus 为“9000”且result_code
                    // 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
                    if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {
                        // 获取alipay_open_id,调支付时作为参数extern_token 的value
                        // 传入,则支付账户为该授权账户
                        Toast.makeText(AliPayLoginActivity.this, "授权成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT) show();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                 // 向服务端发送请求,预计返回用户信息数据,返回给前端进行显示。
                                String url = "http://exzg5x.natappfree.cc" +
                                        "/alipay/getalipayMobileUserInfo" + "?" +
                                        "app_id=" + Constants.ALPAY_APP_ID +
                                       "&auth_code=" + authResult.getAuthCode() +
                                        "&scope=auth_user";
                                String str = ApacheHttpUtil.get(url);
                                JSONObject jsonObject =  (JSONObject) JSONObject.parse(str);
                                aliPayUserInfo = (AliPayUserInfo)JSON.parseObject(jsonObject.get("data").toString(), new TypeReference() {});
                            }
                        }).start();

                        while (true){
                            // TODO: 这里处理方案不是很合理,死循环或将造成界面卡死
                            if (aliPayUserInfo!=null){
                                Intent intent = new Intent(AliPayLoginActivity.this, listviewItem.class);
                                /* 通过Bundle对象存储需要传递的数据 */
                                Bundle bundle = new Bundle();
                                bundle.putString("alipayUserId", aliPayUserInfo.getUserId());
                                bundle.putString("alipayAvatar", aliPayUserInfo.getAvatar());
                                bundle.putString("alipayNickName", aliPayUserInfo.getNickName());
                                bundle.putString("alipayCity", aliPayUserInfo.getCity());
                                bundle.putString("alipayGender", aliPayUserInfo.getGender());
                                bundle.putString("alipayIsCertified", aliPayUserInfo.getIs_certified());
                                bundle.putString("alipayIsStudentCertified", aliPayUserInfo.getIs_student_certified());
                                bundle.putString("alipayProvince", aliPayUserInfo.getProvince());
                                bundle.putString("alipayUserStatus", aliPayUserInfo.getUser_status());
                                bundle.putString("alipayUserType", aliPayUserInfo.getUser_type());
                                /*把bundle对象assign给Intent*/
                                intent.putExtras(bundle);
                                startActivity(intent);
                                break;
                            }
                        }
                    } else {
                        // 其他状态值则为授权失败
                        Toast.makeText(AliPayLoginActivity.this, "授权失败" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
                    }
                    break;
                }
                default:
                    break;
            }
        }
        ;
    };

4).AliPayUserInfoViewItem.java:

需要获取Bundle,然后将数据设置到对应控件中。

public class listviewItem extends FragmentActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listview_item);
        Bundle bundle = this.getIntent().getExtras();
        TextView alipayUserId = (TextView) findViewById(R.id.alipayUserId);
        alipayUserId.setText(bundle.getString("alipayUserId"));

        TextView alipayNickName = (TextView) findViewById(R.id.alipayNickName);
        alipayNickName.setText(bundle.getString("alipayNickName"));

        TextView alipayCity = (TextView) findViewById(R.id.alipayCity);
        alipayCity.setText(bundle.getString("alipayCity"));

        TextView alipayGender = (TextView) findViewById(R.id.alipayGender);
        alipayGender.setText(bundle.getString("alipayGender"));

        TextView alipayIsCertified = (TextView) findViewById(R.id.alipayIsCertified);
        alipayIsCertified.setText(bundle.getString("alipayIsCertified"));

        TextView alipayIsStudentCertified = (TextView) findViewById(R.id.alipayIsStudentCertified);
   alipayIsStudentCertified.setText(bundle.getString("alipayIsStudentCertified"));
        TextView alipayProvince = (TextView) findViewById(R.id.alipayProvince);
        alipayProvince.setText(bundle.getString("alipayProvince"));

        TextView alipayUserStatus = (TextView) findViewById(R.id.alipayUserStatus);
        alipayUserStatus.setText(bundle.getString("alipayUserStatus"));

        TextView alipayUserType = (TextView) findViewById(R.id.alipayUserType);
        alipayUserType.setText(bundle.getString("alipayUserType"));
    }

2.服务端(Java)

1).服务端加签

@ResponseBody
@RequestMapping("/sign/{type}")
public String sign(@PathVariable("type") String type){
    if (!StringUtils.isEmpty(type)&&type.equals("android")){
        Map authInfoMap = OrderInfoUtil2_0.buildAuthInfoMap(
                env.getProperty("alipay.pid"),
                env.getProperty("alipay.appid"),
                env.getProperty("alipay.targetId"), true);
        String info = OrderInfoUtil2_0.buildOrderParam(authInfoMap);
        String privateKey = env.getProperty("alipay.privatekey");
        String sign = OrderInfoUtil2_0.getSign(authInfoMap, privateKey, true);
        final String authInfo = info + "&" + sign;
        return authInfo;
    }
    return null;
}

2).配置

增加配置pid以及targetId。

其中pid为商户pid,targetId为商户自定义的id

# 商户pid
alipay.pid =

# TARGET_ID
# 支付宝账户登录授权业务:入参target_id值,这个target_id参数是商户自定义的,不需要获取。
alipay.targetId =

 

3).获取用户信息

@ResponseBody
    @RequestMapping("/getalipayMobileUserInfo")
    public Result getALiPayMobileUserInfo(HttpServletRequest httpServletRequest) {
        String appId = httpServletRequest.getParameter("app_id");
        String scope = httpServletRequest.getParameter("scope");
        String authCode = httpServletRequest.getParameter("auth_code");
        if (appId == null || scope == null || authCode == null ){
            Result.error(CodeMsg.PARAM_ISNULL);
        }
        // 判定appid是否是我们的 Android传过来的Appid和服务单Appid有点差异
        if(!appId.contains(env.getProperty("alipay.appid").trim())){
            Result.error(CodeMsg.ILLEGAL_PARAM);
        }
        AlipayClient alipayClient = new DefaultAlipayClient(
                env.getProperty("alipay.serverUrl"),
                env.getProperty("alipay.appid"),
                env.getProperty("alipay.privatekey"),
                "json", "UTF-8",
                env.getProperty("alipay.publickey"),
                "RSA2"); //获得初始化的AlipayClient

        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();//创建API对应的request类
        request.setCode(authCode);
        request.setGrantType("authorization_code");
        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类
            log.info("AccessToken:"+oauthTokenResponse.getAccessToken());
            // 获取用户信息
            AliPayUserInfo aliPayUserInfo = getAliPayUserInfo(alipayClient,oauthTokenResponse.getAccessToken());
            if (aliPayUserInfo==null){
                Result.error(CodeMsg.FAIL_GETUSERINFO);
            }
            // 统一返回结果。
            return Result.success(aliPayUserInfo);
        } catch (AlipayApiException e) {
            //处理异常
            e.printStackTrace();
        }
        return Result.error(CodeMsg.UNKNOW_ERROR);
    }

 

五、注意事项:

1.Android4.0以上版本,发送网络请求时,必须是以线程异步的方式发送请求,否则发送请求会失败。

 

 

附录:

App支付宝登录授权参数

https://docs.open.alipay.com/218/105327

 

你可能感兴趣的:(支付宝,第三方授权登录)