获取用户信息

可以通过该流程获取用户的 手机号、头像、昵称 等信息

简要流程

开发者主要操作步骤:

  1. 开发者小程序通过 isHostLogin 判断用户是否登录,未登录时使用 appLogin 唤起登录页面并完成登录(逻辑请参考 getUserId, 本章节略)
  2. 开发者通过 getUserData 获取授权令牌
  3. 开发者通过后台效用小程序开放平台接口/api/developer/user/info换取用户信息

流程图如下所示:

详细步骤

1. 开发者小程序通过 isHostLogin 判断用户是否登录,未登录时使用 appLogin 唤起登录页面并完成登录(逻辑请参考 登录流程 getUserId, 本章节略)

2. 开发者通过 getUserData 获取授权令牌

相关接口如下:

getUserData(OBJECT)


OBJECT参数说明:

参数名 类型 必填 说明
authFields String 需要授权的字段code, 目前一次只能授权一个字段, 可用字段见下方
success Function 成功处理时的回调函数
fail Function 处理失败时的回调函数

用户信息字段:

字段名称 字段 code
albumUrl 头像
nickName 昵称
mobile 手机号
carNo 车牌号
frameNo 车架号
realName 姓名
idNo 身份证
passport 护照
residencePermit 留居证
sex 性别
email 邮箱
address 收货信息

success返回参数说明:

回参数据结构为 {"data":{"userInfoCode":"xxxxx"}}, 需要取 data 数据, data 数据结构如下

参数 类型 说明
userInfoCode String 授权令牌

fail返回参数说明:

参数 类型 说明
errCode String 异常编码
msg String 异常信息

调用示例

PAMINA.call('getUserData', {authFields: "mobile"}, (res) => {
    // 用户同意授权, 此处会返回 mobile 的授权查询令牌
    console.log(res);
  }, (e) => {
    // 用户拒绝授权
    console.log(e);
})

3. 开发者通过后台效用小程序开放平台接口/api/developer/user/info换取用户信息


这是一个 HTTPS 接口,开发者通过后台服务器 使用 授权令牌 从小程序开放平台换取指定的用户信息字段。

为了保证数据安全,开发者需要使用 RSA 密钥进行身份认证,RSA 密钥可以从小程序开放平台如下入口获取: 开发中心 -> 你的小程序 -> 基础信息 -> 小程序密钥

在完成上线全部流程前只能通过测试环境接口方式联调,完成上线流程后需再切换为生产环境接口地址。其中调用测试接口联调时需要提供手机号和设备号给产险开发添加测试数据

令牌接口地址

在完成业务接口调用前需要调用访问令牌接口获取access_token,获取到的acess_token在调用业务接口是放到url后面。

测试地址
POST https://test-api.pingan.com.cn:20443/oauth/oauth2/access_token
生产地址
POST https://api.pingan.com.cn/oauth/oauth2/access_token

请求参数

具体入参值可找产险开发老师获取。

传值方式 参数值
client_id POST 请求 应用ID 例如:P_PA002_ELIS_UWS(在“我的应用”列表中)
grant_type POST 请求 授权类型 固定值:client_credentials
client_secret POST 请求 应用密钥 例如:znD5x4d1(创建应用时返回的应用密码)

响应参数

access_token oauth系统对获取access_token有调用限制,请将获取的token值放到本地缓存;注意token是有有效期的,当token失效时需要做相应处理。
expires_in 有效期 例如 :60 (单位:分钟);0表示永久有效;expires_in只是有效期参考,不以这个为唯一更新token的标准。注意调用接口返回13002和13012的错误码必须处理。
openid openid

具体指引链接:https://api.pingan.com.cn/dev/index.do?bAPhdWDKZYpPM00

业务接口地址

测试地址
POST https://test-api.pingan.com.cn:20443/open/mina-store/api/stg/developer/user/info?access_token=C89B2C0D6A4D4262B17CD7DC1EC05E11&request_id=123451
生产地址
POST https://api.pingan.com.cn/open/mina-store/api/developer/user/info?access_token=C89B2C0D6A4D4262B17CD7DC1EC05E11&request_id=123451

Headers

参数名称 参数值 是否必须 备注
Content-Type application/json
X-MINA-MINI-APP-ID 小程序ID
X-MINA-TIMESTAMP 请求时间(毫秒级)
X-MINA-SIGN 请求签名, 签名有效时间 60 秒, 采用 RSA 算法, 签名结果使用 Base64 进行编码;签名格式:
RSA(requestBodyString + X-MINA-MINI-APP-ID + X-MINA-TIMESTAMP)

请求参数

名称 类型 是否必须 默认值 备注
miniAppId string 小程序ID,可从端能力getSystemInfo获取
deviceId string 设备ID,获取途径同miniAppId
hostAppId string 宿主渠道,如PA00300000000_01_HCZ,获取途径同miniAppId
userInfoCode string 一次性授权令牌,有效时间 60 秒,可从getUserData获取

响应参数

名称 类型 是否必须 默认值 备注
responseCode string 默认0为成功
responseMsg string 提示信息
data object 业务数据
└─ encrypted string 加密后的用户信息。
本字段为AES(AES/GCM/NoPadding)加密的字符串,采用 base64 编码;
AES 密钥使用 userInfoCode 生成, 见下方示例。解密后后为json格式

调用示例

axios(
    {
        method: "post",
        url: `https://api.pingan.com.cn/open/mina-store/api/developer/user/info`,
        data: '', // 入参
        headers: {} // 请求头
    }
).then((res) => {
    console.log("msgSend---sucess", res);
    this.msgSendResult = JSON.stringify(res);
})

完整代码示例


示例代码(前端 vue):

export default {
  name: "getUserData",
  data() {
    return {
      authFields: "mobile",
      getUserDataResult: null,
    }
  },
  methods: {
    getUserData() {
      PAMINA.call('getUserData', {authFields: this.authFields}, (res) => {
          console.log(res);
          this.getUserDataResult = res;
          if (res.data === undefined && res.errMsg === 'getUserData:ok') {
            this.getUserData();
          }
        }, (e) => {
          console.log(e)
          this.getUserDataResult = JSON.stringify(e)
          this.$toast(e.msg)
      })
    },
    getDeveloperUserInfo(code) {
      if (this.getDeviceIDResult === '') {
        this.$toast('请先获取设备ID');
        return;
      }
      if (this.getUserDataResult.data === undefined) {
        this.$toast('请先获取授权令牌');
        return;
      }
      // code = 'a8c48ca5bc9e4a19b037947f00602222';
      if (code === undefined) {
        code = this.getUserDataResult.data.userInfoCode;
      }
      var now_timestamp = new Date().getTime();

      var reqBody = JSON.stringify({
        "miniAppId": "cxec128d79635042d7", // 小程序ID,可从端能力getSystemInfo获取
        "deviceId": '', // 设备id, 可从端能力getSystemInfo获取
        "hostAppId": "PA00300000000_01_HCZ",  // 宿主渠道, 可从端能力getSystemInfo获取
        "userInfoCode": code.replace(/\s+/g, ""), // 一次性授权令牌
      });

      console.log('getDeveloperUserInfo---reqBody:', reqBody);

      let bodyJson = JSON.parse(reqBody);

      let appId = bodyJson.miniAppId;

      var signstr = reqBody + appId + now_timestamp;

      console.log("signString : " + signstr);

      let key ="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2UkXBU/RVl...."; // 秘钥

      console.log("getDeveloperUserInfo---privateKey : " + key)

      let sign = this.signRsa(key,signstr);
      const header = {
        "Content-Type": 'application/json',
        "X-MINA-TIMESTAMP": now_timestamp,
        "X-MINA-SIGN": sign,
        "X-MINA-MINI-APP-ID": appId
      };
      console.log('getDeveloperUserInfo---header:', header);

      axios(
        {
          method: "post",
          url: `https://api.pingan.com.cn/open/mina-store/api/developer/user/info`,
          data: bodyJson,
          headers: header
        }
      ).then((res) => {
          console.log("getDeveloperUserInfo---sucess", res);
          this.getDeveloperUserInfoResult = JSON.stringify(res);
      })
      .catch((e) => {
        console.log("getDeveloperUserInfo---fail", e);
        this.getDeveloperUserInfoResult = JSON.stringify(e);
      });
    },

    signRsa(encrypt_key, clearText){
      console.info('cleartext: ' + clearText);
      //注意此处上下的BEGIN PRIVATE KEY不要删除,框架自带的
      const private_key = '-----BEGIN PRIVATE KEY-----\n'
              + encrypt_key
              + '\n-----END PRIVATE KEY-----';
      // !!!请自行下载Forge加密js包引入
      var privateKey = forge.pki.privateKeyFromPem(private_key);

      // const md = forge.md.sha1.create();//这里的sha1对应的java的SHA1WithRSA
      const md = forge.md.sha256.create();

      md.update(clearText,"utf8"); 
      let sig = privateKey.sign(md);
      let erg = forge.util.encode64(sig);
      console.log("Signature is: "+erg);
      return erg;
    },
  }
}

示例代码(后端 java):加密

基础方法


    /**
     * 初始化安全提供者
     */
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * 解密方法
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     */
    public static String decrypt(
            byte[] data, byte[] key
    ) throws IllegalBlockSizeException, BadPaddingException,
            NoSuchPaddingException, NoSuchAlgorithmException,
            UnsupportedEncodingException, InvalidAlgorithmParameterException, InvalidKeyException {

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

        // 初始化,设置解密模式
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(key));

        // 执行操作
        return new String(cipher.doFinal(data), "UTF-8");

    }

    /**
     * 根据String 生成 密钥
     * @param code 字符串
     * @param keySize 密钥位数, 例如 128/192/256
     * @return 二进制密钥
     */
    public static byte[] getKey(String code, int keySize) {

        int keyByteSize = keySize / 8;

        byte[] aesBytes = new byte[keyByteSize];

        System.arraycopy(code.getBytes(), 0, aesBytes, 0, keyByteSize);

        SecretKeySpec aes = new SecretKeySpec(aesBytes, "AES");

        return aes.getEncoded();
    }

解密用户数据( 对应 response.data.encrypted 字段)

import org.apache.commons.codec.binary.Base64;

public static void main(String[] args) {
  // 1. 根据 userInfoCode 生成 AES 密钥
  byte[] aesKeyBytes = getKey(code, 128);

  // 2. 解密用户信息(import org.apache.commons.codec.binary.Base64;)
  String decryptedUserInfoBytes = decrypt(Base64.decodeBase64(encryptedUserInfo), aesKeyBytes);
}
小程序团队 © 2020-2021 all right reserved,powered by Gitbook文件修订时间: 2026-01-05 11:12:01

results matching ""

    No results matching ""