小程序之~~基于微信登录,后台代码

、登录流程图

技术分享图片

 

二、微信小程序端

  1.  
    doLogin:
    function(callback = () =>{}){

  2.  
    let that = this;

  3.  
    wx.login({

  4.  
    success:function(loginRes){

  5.  
    if(loginRes){

  6.  
    //获取用户信息

  7.  
    wx.getUserInfo({

  8.  
    withCredentials:true,//非必填 默认为true

  9.  
    success:
    function(infoRes){

  10.  
    console.log(infoRes,‘>>>‘);

  11.  
    //请求服务端的登录接口

  12.  
    wx.request({

  13.  
    url: api.loginUrl,

  14.  
    data:{

  15.  
    code:loginRes.code,//临时登录凭证

  16.  
    rawData:infoRes.rawData,
    //用户非敏感信息

  17.  
    signature:infoRes.signature,
    //签名

  18.  
    encrypteData:infoRes.encryptedData,
    //用户敏感信息

  19.  
    iv:infoRes.iv
    //解密算法的向量

  20.  
    },

  21.  
    success:function(res){

  22.  
    console.log(‘login success‘);

  23.  
    res = res.data;

  24.  
    if(res.result==0){

  25.  
    that.globalData.userInfo = res.userInfo;

  26.  
    wx.setStorageSync(
    ‘userInfo‘,JSON.stringify(res.userInfo));

  27.  
    wx.setStorageSync(
    ‘loginFlag‘,res.skey);

  28.  
    console.log("skey="+res.skey);

  29.  
    callback();

  30.  
    }
    else{

  31.  
    that.showInfo(
    ‘res.errmsg‘);

  32.  
    }

  33.  
    },

  34.  
    fail:function(error){

  35.  
    //调用服务端登录接口失败

  36.  
    // that.showInfo(‘调用接口失败‘);

  37.  
    console.log(error);

  38.  
    }

  39.  
    });

  40.  
    }

  41.  
    });

  42.  
    }
    else{

  43.  
     
  44.  
    }

  45.  
    }

  46.  
    });

  47.  
    }

微信小程序端发起登录请求,携带的参数主要有:

  1.  
    code:loginRes.code,
    //临时登录凭证

  2.  
    rawData:infoRes.rawData,
    //用户非敏感信息

  3.  
    signature:infoRes.signature,
    //签名

  4.  
    encrypteData:infoRes.encryptedData,
    //用户敏感信息

  5.  
    iv:infoRes.iv
    //解密算法的向量

需要的数据主要有:

result、userInfo和skey

result用来判断是否登录成功,userInfo是用户的一些信息,保存在缓存中,不用每次都从后台获取,skey是用户登录态标识,也放在缓存中,如果skey存在就直接登录,维护用户的登录状态,具有时效性

三、Java后台

  1.  
    @ResponseBody

  2.  
    @RequestMapping(
    "/login")

  3.  
    public
    Map<String,Object> doLogin(Model model,

  4.  
    @RequestParam(value =
    "code",required = false) String code,

  5.  
    @RequestParam(value =
    "rawData",required = false) String rawData,

  6.  
    @RequestParam(value =
    "signature",required = false) String signature,

  7.  
    @RequestParam(value =
    "encrypteData",required = false) String encrypteData,

  8.  
    @RequestParam(value =
    "iv",required = false) String iv){

  9.  
    log.info(
    "Start get SessionKey" );

  10.  
     
  11.  
     
  12.  
    Map<String,Object> map = new HashMap<String, Object>( );

  13.  
    System.out.println(
    "用户非敏感信息"+rawData);

  14.  
     
  15.  
    JSONObject rawDataJson =
    JSON.parseObject( rawData );

  16.  
     
  17.  
    System.out.println(
    "签名"+signature);

  18.  
    JSONObject SessionKeyOpenId = getSessionKeyOrOpenId( code );

  19.  
    System.out.println(
    "post请求获取的SessionAndopenId="+SessionKeyOpenId);

  20.  
     
  21.  
    String openid = SessionKeyOpenId.getString("openid" );

  22.  
     
  23.  
    String sessionKey = SessionKeyOpenId.getString( "session_key" );

  24.  
     
  25.  
    System.out.println(
    "openid="+openid+",session_key="+sessionKey);

  26.  
     
  27.  
    User user = userService.findByOpenid( openid );

  28.  
    //uuid生成唯一key

  29.  
    String skey = UUID.randomUUID().toString();

  30.  
    if(user==null){

  31.  
    //入库

  32.  
    String nickName = rawDataJson.getString( "nickName" );

  33.  
    String avatarUrl = rawDataJson.getString( "avatarUrl" );

  34.  
    String gender = rawDataJson.getString( "gender" );

  35.  
    String city = rawDataJson.getString( "city" );

  36.  
    String country = rawDataJson.getString( "country" );

  37.  
    String province = rawDataJson.getString( "province" );

  38.  
     
  39.  
     
  40.  
    user =
    new User();

  41.  
    user.setUid( openid );

  42.  
    user.setCreateTime(
    new Date( ) );

  43.  
    user.setSessionkey( sessionKey );

  44.  
    user.setUbalance(
    0 );

  45.  
    user.setSkey( skey );

  46.  
    user.setUaddress( country+
    " "+province+" "+city );

  47.  
    user.setUavatar( avatarUrl );

  48.  
    user.setUgender( Integer.parseInt( gender ) );

  49.  
    user.setUname( nickName );

  50.  
    user.setUpdateTime(
    new Date( ) );

  51.  
     
  52.  
    userService.insert( user );

  53.  
    }
    else {

  54.  
    //已存在

  55.  
    log.info(
    "用户openid已存在,不需要插入" );

  56.  
    }

  57.  
    //根据openid查询skey是否存在

  58.  
    String skey_redis = (String) redisTemplate.opsForValue().get( openid );

  59.  
    if(StringUtils.isNotBlank( skey_redis )){

  60.  
    //存在 删除 skey 重新生成skey 将skey返回

  61.  
    redisTemplate.delete( skey_redis );

  62.  
     
  63.  
    }

  64.  
    // 缓存一份新的

  65.  
    JSONObject sessionObj =
    new JSONObject( );

  66.  
    sessionObj.put(
    "openId",openid );

  67.  
    sessionObj.put(
    "sessionKey",sessionKey );

  68.  
    redisTemplate.opsForValue().set( skey,sessionObj.toJSONString() );

  69.  
    redisTemplate.opsForValue().set( openid,skey );

  70.  
     
  71.  
    //把新的sessionKey和oppenid返回给小程序

  72.  
    map.put(
    "skey",skey );

  73.  
     
  74.  
     
  75.  
     
  76.  
    map.put(
    "result","0" );

  77.  
     
  78.  
     
  79.  
     
  80.  
    JSONObject userInfo = getUserInfo( encrypteData, sessionKey, iv );

  81.  
    System.out.println(
    "根据解密算法获取的userInfo="+userInfo);

  82.  
    userInfo.put(
    "balance",user.getUbalance() );

  83.  
    map.put(
    "userInfo",userInfo );

  84.  
     
  85.  
    return map;

  86.  
    }

获取openid和sessionKey方法

  1.  
    public
    static JSONObject getSessionKeyOrOpenId(String code){

  2.  
    //微信端登录code

  3.  
    String wxCode = code;

  4.  
    String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";

  5.  
    Map<String,String> requestUrlParam = new HashMap<String, String>( );

  6.  
    requestUrlParam.put(
    "appid","你的小程序appId" );//小程序appId

  7.  
    requestUrlParam.put(
    "secret","你的小程序appSecret" );

  8.  
    requestUrlParam.put(
    "js_code",wxCode );//小程序端返回的code

  9.  
    requestUrlParam.put(
    "grant_type","authorization_code" );//默认参数

  10.  
     
  11.  
    //发送post请求读取调用微信接口获取openid用户唯一标识

  12.  
    JSONObject jsonObject =
    JSON.parseObject( UrlUtil.sendPost( requestUrl,requestUrlParam ));

  13.  
    return jsonObject;

  14.  
    }

解密用户敏感数据获取用户信息

 

  1.  
    public static JSONObject getUserInfo(String encryptedData,String sessionKey,String iv){

  2.  
    // 被加密的数据

  3.  
    byte[] dataByte = Base64.decode(encryptedData);

  4.  
    // 加密秘钥

  5.  
    byte[] keyByte = Base64.decode(sessionKey);

  6.  
    // 偏移量

  7.  
    byte[] ivByte = Base64.decode(iv);

  8.  
    try {

  9.  
    // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要

  10.  
    int base = 16;

  11.  
    if (keyByte.length % base != 0) {

  12.  
    int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);

  13.  
    byte[] temp = new byte[groups * base];

  14.  
    Arrays.fill(temp, (
    byte) 0);

  15.  
    System.arraycopy(keyByte,
    0, temp, 0, keyByte.length);

  16.  
    keyByte = temp;

  17.  
    }

  18.  
    // 初始化

  19.  
    Security.addProvider(
    new BouncyCastleProvider());

  20.  
    Cipher cipher = Cipher.getInstance(
    "AES/CBC/PKCS7Padding","BC");

  21.  
    SecretKeySpec spec =
    new SecretKeySpec(keyByte, "AES");

  22.  
    AlgorithmParameters parameters = AlgorithmParameters.getInstance(
    "AES");

  23.  
    parameters.init(
    new IvParameterSpec(ivByte));

  24.  
    cipher.init( Cipher.DECRYPT_MODE, spec, parameters);
    // 初始化

  25.  
    byte[] resultByte = cipher.doFinal(dataByte);

  26.  
    if (null != resultByte && resultByte.length > 0) {

  27.  
    String result =
    new String(resultByte, "UTF-8");

  28.  
    return JSON.parseObject(result);

  29.  
    }

  30.  
    }
    catch (NoSuchAlgorithmException e) {

  31.  
    log.error(e.getMessage(), e);

  32.  
    }
    catch (NoSuchPaddingException e) {

  33.  
    log.error(e.getMessage(), e);

  34.  
    }
    catch (InvalidParameterSpecException e) {

  35.  
    log.error(e.getMessage(), e);

  36.  
    }
    catch (IllegalBlockSizeException e) {

  37.  
    log.error(e.getMessage(), e);

  38.  
    }
    catch (BadPaddingException e) {

  39.  
    log.error(e.getMessage(), e);

  40.  
    }
    catch (UnsupportedEncodingException e) {

  41.  
    log.error(e.getMessage(), e);

  42.  
    }
    catch (InvalidKeyException e) {

  43.  
    log.error(e.getMessage(), e);

  44.  
    }
    catch (InvalidAlgorithmParameterException e) {

  45.  
    log.error(e.getMessage(), e);

  46.  
    }
    catch (NoSuchProviderException e) {

  47.  
    log.error(e.getMessage(), e);

  48.  
    }

  49.  
    return null;

  50.  
    }

 

四、流程

1.小程序端发起请求并携带主要参数

2.java后台接到/login请求后,根据code去调用微信接口获取用户唯一标识openid和sessionKey

3.根据openid查询mysql数据库,判断该用户是否存在,如果不存在将用户非敏感信息和其他初始化数据存入到数据库中,如果已存在,不操作

4.根据openid查询redis数据库,判断openid对应的skey是否存在,如果存在则删除原来老的skey以及对应的openid和sessionKey

5.通过uuid生成唯一的skey,用openid做键,skey做值,存入到redis中

6.然后把skey做键,openid和sessionKey的json串做值也重新存入到redis中

7.根据解密算法,参数有encryptedData、sessionKey和iv,获取用户信息userInfo,如果userInfo字段不满足需要,可通过userInfo.put( "balance",user.getUbalance() );添加所需要的字段和值

8.将微信小程序需要的数据封装到map中,返回给小程序端

    1.  
      map.put( "skey",skey );

    2.  
       
    3.  
      map.put( "result","0" );

    4.  
       
    5.  
      map.put( "userInfo",userInfo );

    6.  
       
    7.  

相关文章