2015-12-16 15:06:06 myfmyfmyfmyf 阅读数 3423
  • 微信沙箱开发微信社交立减金接口升级

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信沙箱也叫微信仿真测试系统,微信沙箱开发是子恒老师《子恒说微信开发》视频教程的第18部。详细讲解了微信沙箱开发过程,内容包含微信沙箱作用,获取微信沙箱验签秘钥KEY,在沙箱中实现社交立减金接口升级等等。欢迎反馈,微信号:QQ68183131

    7156 人正在学习 去看看 秦子恒
       OAuth验证接口作用是当微信中的页面访问后台时,能够使后台知道是不是企业内部人员访问,是哪个员工访问,从而可以做相应的处理

---------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------

1、处理页面链接,使后台能获得微信提供的code

      对我们自己的链接进行urlencode处理,处理方法

     

var changeurl=getUrl.replace(/[:]/g,"%3a").replace(/[/]/g,"%2f").replace(/[\?]/g,"%3f").replace(/[=]/g,"%3d").replace(/[&]/g,"%26");
var tourl="https://open.weixin.qq.com/connect/oauth2/authorize?appid=自己的appid&redirect_uri="+changeurl+"&response_type=code&scope=snsapi_base&state=location#wechat_redirect";

企业获取code

企业如果需要员工在跳转到企业网页时带上员工的身份信息,需构造如下的链接:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

  • 参数说明
参数 必须 说明
appid 企业的CorpID
redirect_uri 授权后重定向的回调链接地址,请使用urlencode对链接进行处理
response_type 返回类型,此时固定为:code
scope 应用授权作用域,此时固定为:snsapi_base
state 重定向后会带上state参数,企业可以填写a-zA-Z0-9的参数值,长度不可超过128个字节
#wechat_redirect 微信终端使用此参数判断是否需要带上身份信息

员工点击后,页面将跳转至 redirect_uri?code=CODE&state=STATE,企业可根据code参数获得员工的userid。

---------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------


2、后台根据code获得获得uesid

/**
  	 * 根据code获得人员
  	 */
  	public String getUserIdByCode(String code){
  	//获取微信号
    	String token=getTokenFromWx();
		 try {
			 CloseableHttpClient httpclient = HttpClients.createDefault();
			 HttpPost httpPost= new HttpPost("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token="+token+"&code="+code+"&agentid="+AGENT_ID_REGISTER);
			 // Create a custom response handler
			 ResponseHandler<JSONObject> responseHandler = new ResponseHandler<JSONObject>() {

                public JSONObject handleResponse(
                        final HttpResponse response) throws ClientProtocolException, IOException {
                    int status = response.getStatusLine().getStatusCode();
                    if (status >= 200 && status < 300) {
                        HttpEntity entity = response.getEntity();
                        if(null!=entity){
                        	String result= EntityUtils.toString(entity);
                            //根据字符串生成JSON对象
                   		 	JSONObject resultObj = JSONObject.fromObject(result);
                   		 	return resultObj;
                        }else{
                        	return null;
                        }
                    } else {
                        throw new ClientProtocolException("Unexpected response status: " + status);
                    }
                }

            };
          //返回的json对象
            JSONObject responseBody = httpclient.execute(httpPost, responseHandler);
            //AppLogUtil.getAppLoger().info(responseBody.toString());
            if(null==responseBody.getString("UserId")){
            	return null;
            }else{
            	return responseBody.getString("UserId"); 
            }
		 }catch (Exception e) {
			//e.printStackTrace();
			return null;
		}
  	}

官网API:http://qydev.weixin.qq.com/wiki/index.php?title=OAuth验证接口


2018-11-23 11:36:56 sunon_ 阅读数 923
  • 微信沙箱开发微信社交立减金接口升级

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信沙箱也叫微信仿真测试系统,微信沙箱开发是子恒老师《子恒说微信开发》视频教程的第18部。详细讲解了微信沙箱开发过程,内容包含微信沙箱作用,获取微信沙箱验签秘钥KEY,在沙箱中实现社交立减金接口升级等等。欢迎反馈,微信号:QQ68183131

    7156 人正在学习 去看看 秦子恒

先说一下需求吧,小程序微信登录,用户授权获取个人信息。然后保存用户基本信息到系统用户表,同时新增用户账户信息,上传用户头像。

emmm..之所以想写下来是因为自己踩过的坑啊。。就不细说了。


链接: 小程序微信登录官方文档

 

登录:

之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

用户授权获取个人信息:

wx.getUserInfo(OBJECT)

注意:此接口有调整,使用该接口将不再出现授权弹窗,请使用 <button open-type="getUserInfo"></button> 引导用户主动进行授权操作

注:当 withCredentials 为 true 时,要求此前有调用过 wx.login 且登录态尚未过期,此时返回的数据会包含 encryptedData, iv 等敏感信息;当 withCredentials 为 false 时,不要求有登录态,返回的数据不包含 encryptedData, iv 等敏感信息。

 

这是官方给的文档写的。就是前端调用微信接口得到一个code和useInfo,把这两个给后台,后台首先通过code走微信提供的链接获取到用户唯一标识openid 和 会话密钥session_key。

1

2

3

String token = HttpUtil.doPost("n 

?appid=" + prop.get(APP_ID)+ "&secret=" + prop.get(API_KEY) +

 "&js_code=" code "&grant_type=authorization_code", null, "UTF-8");

效验成功返回一个

//正常返回的JSON数据包{  	"openid": "OPENID",  	"session_key": "SESSIONKEY"}

效验失败返回

1

2

//错误时返回JSON数据包(示例为Code无效){  "errcode"40029,  "errmsg": "invalid

 code"}

效验成功后,然后是根据参数useInfo获取用户的信息。利用上面得到的openId和sessionkey

小程序可以通过各种前端接口获取微信提供的开放数据。 考虑到开发者服务器也需要获取这些开放数据,微信会对这些数据做签名和加密处理。 开发者后台拿到开放数据后可以对数据进行校验签名和解密,来保证数据不被篡改。

为了确保 开放接口 返回用户数据的安全性,微信会对明文数据进行签名。开发者可以根据业务需要对数据包进行签名校验,确保数据的完整性。

1

2

3

4

5

6

7

8

9

JSONObject userInfo = JSONObject.parseObject(userInfo);

        // 用户信息

        // 签名校验

        if (!new String(SecureUtil.sha1X16(userInfo.get(WX_RAWDATA) 

        + sessionKey, ENCODING_FORMAT), ENCODING_FORMAT)

            .equals(userInfo.getString(WX_SIGNATURE))) {

            renderJson(Result.fail("签名校验失败").build());

            return;

        }

签名效验成功后,解密加密的数据

1

2

3

4

5

6

7

8

// 加密数据解密

        JSONObject userInfoEncrypted =

            desEncrypt(userInfo.getString(WX_ENCRYPTEDDATA), sessionKey,

             userInfo.getString(WX_IV));

        if (null == userInfoEncrypted) {

            renderJson(Result.fail("数字水印校验失败").build());

            return;

        }

解密完后就是根据自己的需求开发了。

先判断第三方的openid在数据库中是否存在,如果存在则说明用户已经登录过小程序,如果数据库中不存在则用户是首次登录小程序需要将用户信息保存到数据库

1

2

3

4

5

6

7

8

9

10

11

12

 // 判断是否已注册

        String openId = userInfoEncrypted.getString(WX_USERINFO_OPEN_ID);

        MemberUser user = memberUserService.find(new MemberUser().setOpenId(openId));

        //已注册

        if (Tools.isNotEmpty(user)) {

            MemberInfo info = memberInfoService.find(new MemberInfo()

            .setUserId(user.getUserId()));

            result = assembleResult(user, info, userInfoEncrypted

            .getString(WX_USERINFO_NICKNAME), sessionKey);

            renderJson(Result.ok().put(result).build());

            return;

        }

如果未注册过,就进行注册绑定,把openId保存到第三方绑定表,然后主键为用户表的外键。同时新增用户账户数据。把头像上传到自己服务器。

设置微信手机号绑定一样的。

 

注意:

1、加密解密需要注意,userinfo和绑定手机号需要的phoneinfo都需要效验签名解密获得。效验解密方法官方文档也给出了例子。

2、返回给前端的openId需要加密处理,防止被篡改。

3、注意微信昵称的

完整代码贴到下面,前端代码我就不说了,登录接口需要前端给两个参数:

1、code (登录凭证)

code String 用户登录凭证(有效期五分钟)。开发者需要在开发者服务器后台调用 api,使用 code 换取 openid 和 session_key 等信息

2、 userInfo(用户信息)

rawData String 不包括敏感信息的原始数据字符串,用于计算签名。
signature String 使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息,参考文档 signature
encryptedData String 包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法
iv String 加密算法的初始向量,详细见加密数据解密算法

UserInfo参数:

nickName String 用户昵称
avatarUrl String 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表132*132正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
gender String 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
city String 用户所在城市
province String 用户所在省份
country String 用户所在国家
language String 用户的语言,简体中文为zh_CN

 

完整代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

//参数:

 @Params(value = {@Param(name = "code", dataType = "string"

 in = "formData", description = "code"),

        @Param(name = "userInfo", dataType = "string",

         in = "formData", description = "微信获取用户信息的数据"

         required = true)})

       // 登录:

        public void login() throws Exception {

        Map<String, Object> result = new HashMap<String, Object>();

        // 获取session_key

        Result sessionKeyMap = code2sessionKey(getPara("code"));

        String sessionKey = "";

        if ((boolean)sessionKeyMap.get(Const.RESULT)) {

            sessionKey = String.valueOf(sessionKeyMap.

            get(Const.PROMPT_MSG));

        } else {

            renderJson(sessionKeyMap);

            return;

        }

        JSONObject userInfo = JSONObject.parseObject(getPara("userInfo"));

        // 用户信息

        // 签名校验

        if (!new String(SecureUtil.sha1X16(userInfo.get(WX_RAWDATA)

         + sessionKey, ENCODING_FORMAT), ENCODING_FORMAT)

            .equals(userInfo.getString(WX_SIGNATURE))) {

            renderJson(Result.fail("签名校验失败").build());

            return;

        }

 

        // 加密数据解密

        JSONObject userInfoEncrypted =

            desEncrypt(userInfo.getString(WX_ENCRYPTEDDATA),

             sessionKey, userInfo.getString(WX_IV));

        if (null == userInfoEncrypted) {

            renderJson(Result.fail("数字水印校验失败").build());

            return;

        }

 

        // 判断是否已注册

        String openId = userInfoEncrypted.getString(WX_USERINFO_OPEN_ID);

        MerchantThird user = merchantThirdService.

        find(new MerchantThird().setOpenId(openId));

        if (Tools.isNotEmpty(user)) {

            MerchantInfo info = merchantInfoService

            .findById(user.getMerchantId());

            if (info == null) {

                return;

            }

            SysUser sysUser = sysUserService

            .findById(info.getUserId());

 

            result = assembleResult(user, info, sysUser, 

            userInfoEncrypted.getString(WX_USERINFO_NICKNAME),

             sessionKey);

            renderJson(Result.ok().put(result).build());

            return;

        }

        result.put("msg""该用户没有注册为医生");

        result.put("token", JWTUtil.createToken(openId, sessionKey));

        renderJson(Result.ok().put(result).build());

    }

 

        /**

     * 微信code换取sessionKey等加密信息

     

     * @param code

     * @return

     */

    private Result code2sessionKey(String code) {

 

        String token = HttpUtil.doPost("https://api.weixin.qq.com/sn

        s/jscode2session?appid=" + prop.get(APP_ID)

            "&secret=" + prop.get(API_KEY) + "&js_code="

             code "&grant_type=authorization_code", null,

              "UTF-8");

        JSONObject jsonObject = JSONObject.parseObject(token);

        if (null != jsonObject.get(WX_ERROR_CODE)) {

            return Result.fail(jsonObject.getString(WX_ERROR_MSG) 

            "(" + jsonObject.getString(WX_ERROR_CODE) + ")")

                .build();

        } else {

            return Result.ok(jsonObject.getString(WX_SESSION_KEY))

            .build();

        }

    }

  /**

     * 聚合用户账号信息

     */

    private MemberUser assembleMemberUser(JSONObject userInfoEncrypted, Date date) {

        return new MemberUser().setUserId(Tools.getUniqueId())

        .setCreationTime(date).setUpdateTime(date)

            .setStatus(Const.DEFAULT_STATUS)

            .setOpenId(userInfoEncrypted.getString(WX_USERINFO_OPEN_ID));

    }

 

    /**

     * 聚合用户信息

     

     * @param userInfoEncrypted 参数集

     * @param date 日期

     * @param userId

     * @return

     */

    private MemberInfo assembleMemberInfo(JSONObject userInfoEncrypted,

     Date date, Long userId) {

        return new MemberInfo().setMemberId(Tools.getUniqueId())

            .setName(filterEmoji(userInfoEncrypted.getString(WX_USERINFO_NICKNAME)

            ,"*")).setType(Const.DEFAULT_STATUS)

            .setAvatar(Tools.getUniqueId()).setSex(userInfoEncrypted.getString

            ("gender").equals("2") ? 1 0)

            .setCreationTime(date).setUpdateTime(date).setUserId(userId)

            .setInvitationCode(String.valueOf(Tools.getRandomNum(10000000,

             99999999)));

    }

  /**

     * 微信水印解密校验

     

     * @param data 加密字符串

     * @param key 密钥

     * @param iv 加密偏移量

     * @return

     * @throws UnsupportedEncodingException

     */

    private JSONObject desEncrypt(String data, String key, String iv) throws

     UnsupportedEncodingException {

        byte[] dataByte =

            AesEncryptUtil.decryptOfDiyIV(Base64.decodeBase64(data),

             Base64.decodeBase64(key), Base64.decodeBase64(iv));

        JSONObject result = JSONObject.parseObject(new String(dataByte, "UTF-8"));

        // 水印校验

        JSONObject watermark = JSONObject.parseObject(String.valueOf(result.

        get(WX_WATERMARK)));

        if (!watermark.getString(WX_WATERMARK_APP_ID).equals(prop.get(APP_ID))) {

            return null;

        }

        return result;

    }

    /**

     

     * @param user 返回的用户账户信息

     * @param info 返回的token内的信息(仅含memberId和openId)

     * @param nickName 返回的昵称

     * @param result 返回的额外内容

     * @return

     */

    private Map<String, Object> assembleResult(MemberUser user, MemberInfo info,

     String nickName, String sessionKey) {

        Map<String, Object> result = new HashMap<String, Object>(6);

        if (Tools.isEmpty(user) || Tools.isEmpty(info)) {

            result.put(Const.RESULT, false);

            result.put(Const.PROMPT_MSG, "获取参数异常");

        }

        info.put(Const.OPEN_ID, user.getOpenId());

        info.put(Const.SESSION_KEY, sessionKey);

        user.remove("openId");

        user.setName(nickName);

        setAvatarMemberUser(user, info);

        result.put("user", user);

        result.put("accountInfo", memberAccountService.find(new MemberAccount()

        .setMemberId(info.getMemberId())));

        result.put("integralInfo", memberIntegralService.find(new MemberIntegral()

        .setMemberId(info.getMemberId())));

        result.put("token", JWTUtil.createToken(info));

        return result;

    }

    1. 小程序调用wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。

    2. 开发者服务器以code换取 用户唯一标识openid 和 会话密钥session_key。

    1. 当用户未授权过,调用该接口将直接进入fail回调

    2. 当用户授权过,可以使用该接口获取用户信息

    1. 通过调用接口(如 wx.getUserInfo)获取数据时,接口会同时返回 rawData、signature,其中 signature = sha1( rawData + session_key )

    2. 开发者将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 即可校验数据的完整性。

2019-05-23 09:29:24 web_snail 阅读数 479
  • 微信沙箱开发微信社交立减金接口升级

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信沙箱也叫微信仿真测试系统,微信沙箱开发是子恒老师《子恒说微信开发》视频教程的第18部。详细讲解了微信沙箱开发过程,内容包含微信沙箱作用,获取微信沙箱验签秘钥KEY,在沙箱中实现社交立减金接口升级等等。欢迎反馈,微信号:QQ68183131

    7156 人正在学习 去看看 秦子恒

公众号信息

 

appid:是公众号开发识别码,配合开发者密码可调用公众号的接口能力。
appsecret:是校验公众号开发者身份的密码,具有极高的安全性。

url接入校验配置

 

URL:就是指我们自己的服务器地址(公网可访问)
该URL是开发者用来接收和响应微信消息和事件的接口URL
(必须以http://或https://开头,分别支持80端口和443端口)
Token:可任意填写,用作生成签名(必须为英文或数字,长度为3-32字符)
该签名在后边会用到,这里暂时随便填个内容也可以

url接入校验流程

当你提交接口配置信息后。
1:首先会发送到微信的服务器上,微信的服务器就会对内容处理
2:微信服务器转发到我们配置的url上(url必须外网可以访问),并带上相应的校验参数
3:我们的服务器接收到请求后,对微信发送的参数进行校验

php校验源码

/**
 * 微信公众号 - 接入接口配置验证
 * 请原样返回echostr参数内容,则接入生效,成为开发者成功
 * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
 * Display a listing of the posts.
 *
 */
public function checkSignature(Request $request)
{
    Log::info('start checkSignature');
    $echostr = $request->get('echostr', '');
    $signature = $request->get('signature', '');
    $timestamp = $request->get('timestamp', '');
    $nonce = $request->get('nonce', '');

    $tmpArr = array($this->token, $timestamp, $nonce);
    sort($tmpArr, SORT_STRING);
    $tmpStr = implode($tmpArr);
    $tmpStr = sha1($tmpStr);
    if($tmpStr == $signature){
        echo $echostr;
        Log::info('checkSignature success');
        exit;
    }else{
        return false;
    }
}

ps: $this->token是你在接口配置信息里设置的token
2019-07-22 11:31:44 zhongguohaoshaonian 阅读数 1091
  • 微信沙箱开发微信社交立减金接口升级

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信沙箱也叫微信仿真测试系统,微信沙箱开发是子恒老师《子恒说微信开发》视频教程的第18部。详细讲解了微信沙箱开发过程,内容包含微信沙箱作用,获取微信沙箱验签秘钥KEY,在沙箱中实现社交立减金接口升级等等。欢迎反馈,微信号:QQ68183131

    7156 人正在学习 去看看 秦子恒

实人认证:是指依托活体检测、人脸比对等生物识别技术、证件OCR识别技术等进行的自然人真实身份的校验服务。
有些业务需求中,我们想要更安全准确的获取用户的真实身份,避免虚假信息的产生,就会要求用户进行实人认证,说的简单点,就是让用户拿着手机对着屏幕摇摇头,张张嘴,眨眨眼之类的,检测人脸动作后,校验真实性。
我们知道,微信公众号开发中,jssdk中只有图片相关的接口方案,并没有捕获人脸相关的接口服务,所以,我们想要实现这一需求,就要使用一些云服务提供的服务方案,这里笔者采用了阿里云的实人认证服务

首先,开发者可以阅读快读入门,了解实人认证的基本流程,以及前期准备,开发者需要使用阿里云账号登录实人认证产品详情页,开通这一业务。

其次,开发者可以直接阅读认证方案,查看H5+服务端接入这一认证方案,App应用可以直接无线SDK+服务端接入这一项。

接口操作流流程如下:
微信端用户调接口向服务器发起认证请求,请求参数中应该带上用户真实姓名,身份证号,身份证正反面图片地址(可不传),这时,服务器向阿里云服务器请求认证,获取认证带有token的URL,并将这一url返回给微信端。
此时,微信端拿到了实人认证的URL路径,直接访问就可以跳转到阿里云的实人认证服务,用户需要做一些摇摇头,眨眨眼,张张嘴之类的动作,就可以完成认证。
一般在认证完成后,我们希望跳转到我们指定的成功或者失败页面,所以,我们可以在跳转这个认证流程页面入口URL之前,添加上两个参数:
1.认证通过跳转URL:{认证流程页面入口URL}&successRedirect={认证通过时重定向URL}
2.认证失败跳转URL:{认证流程页面入口URL}&failRedirect={认证不通过时重定向URL}

重定向URL就是我们前端的页面。
注意:重定向 URL 需要加上协议头,并先使用 encodeURIComponent 编码后再拼接。

时序图如下:
在这里插入图片描述
到这里,实人认证的业务流程基本完毕,主要工作都是由后端开发人员来完成,前段人员只需要通过后台提供的接口获取url即可。


欢迎关注博主:小圣贤君,有问题可以留言哦~

2017-11-06 12:10:12 Fantasy_Jun 阅读数 639
  • 微信沙箱开发微信社交立减金接口升级

    会员免费看,http://edu.csdn.net/lecturer/842右侧可办理会员卡。微信沙箱也叫微信仿真测试系统,微信沙箱开发是子恒老师《子恒说微信开发》视频教程的第18部。详细讲解了微信沙箱开发过程,内容包含微信沙箱作用,获取微信沙箱验签秘钥KEY,在沙箱中实现社交立减金接口升级等等。欢迎反馈,微信号:QQ68183131

    7156 人正在学习 去看看 秦子恒

微信
注册账号:需要一个注册人信息,手机、地址、身份证以及一个微信号
使用接口:需要创建对应应用,需要公司网址、应用图片、应用名称等,审核期限7天以内。
免费接口:分享到朋友圈、发送给朋友、一次性订阅消息(一条订阅)
收费接口:开发者资质(300元/年),支付、登录(app/网站)、卡券、智能接口(语音识别、图像识别、语义理解等),以上需要申请开通
开发者资质认证:(企业)企业全称、组织机构代码、工商执照注册号、法人、经营范围、企业开户名、企业开户银行、企业银行账号、管理员姓名、管理员手机、座机、邮箱、身份证、微信、组织机构代码证扫描件(复印件)、企业工商银业执照、申请公函等

微博
注册账号:(官方注册企业类)需要邮箱、官方注册微博名,(个人)手机号
编辑开发者信息:(公司)需要公司地址、邮编、企业邮箱、企业电话、网站、联系人电话与姓名等
身份认证:身份证、证件照片、手机号、姓名
使用接口:需要创建对应应用,需要应用图片、应用名称、bundle Id、apple Id(上架项目,未上架可以先随意填)等
注意事项:微博的app应用分为上架和未上架(上传app store),未上架的应用在分享时会有提示,登录和分享接口可以使用不收费

qq
注册账号:(企业)需要qq号、公司全称、营业执照注册号、营业执照照片、联系人信息
使用接口:需要创建对应应用,需要一些应用描述
注意事项:平台区分已审核和未审核项目,未审核项目可以使用qq登录和分享接口,不收费

没有更多推荐了,返回首页