微信小程序> 微信小程序与微信网页开发

微信小程序与微信网页开发

浏览量:541 时间: 来源:qq_42342242

微信web开发只需要code值,但是小程序需要一个code值,一个encryptData,一个iv

首先先看图

 

箭头部分为微信给我们的,就是前端需要传过来的。

步骤为:

  1. 小程序客户端调用wx.login,回调里面包含js_code。
  2. 然后将js_code发送到服务器A(开发者服务器),服务器A向微信服务器发起请求附带js_code、appId、secretkey和grant_type参数,以换取用户的openid和session_key(会话密钥)。
  3. 服务器A拿到session_key后,生成一个随机数我们叫3rd_session,以3rdSessionId为key,以session_key + openid为value缓存到redis或memcached中;因为微信团队不建议直接将session_key在网络上传输,由开发者自行生成唯一键与session_key关联。其作用是:
    1. 将3rdSessionId返回给客户端,维护小程序登录态。
    2. 通过3rdSessionId找到用户session_key和openid。
  4. 客户端拿到3rdSessionId后缓存到storage,
  5. 通过wx.getUserIinfo可以获取到用户敏感数据encryptedData 。
  6. 客户端将encryptedData、3rdSessionId和偏移量一起发送到服务器A
  7. 服务器A根据3rdSessionId从缓存中获取session_key
  8. 在服务器A使用AES解密encryptedData,从而实现用户敏感数据解密

 

重点在6、7、8三个环节。
AES解密三个参数:

  • 密文 encryptedData
  • 密钥 aesKey
  • 偏移向量 iv

概念性的东西就这些,下面看代码

首先前端需要传给我们的东西就是三个一个code值,一个encryptData,一个iv,

先写方法

 

package com.everest.academy.util;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import lombok.extern.slf4j.Slf4j;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.util.encoders.Base64;import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.URL;import java.net.URLConnection;import java.security.AlgorithmParameters;import java.security.Security;import java.util.Arrays;import java.util.HashMap;import java.util.Iterator;import java.util.Map;/*** @ClassName XcxUtils* @Description 微信小程序方法* @Author 田野* @Data 22:14* @Version 1.0**/@Slf4jpublic class XcxUtils {/**    * 获取微信小程序 session_key 和 openid    *    * @author zhy    * @param code    *            调用微信登陆返回的Code    * @return    */   public static JSONObject getSessionKeyOropenid(String code, String appid, String secret) {String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; // 请求地址       MapString, String requestUrlParam = new HashMapString, String();       requestUrlParam.put("appid", appid); // 开发者设置中的appId       requestUrlParam.put("secret", secret); // 开发者设置中的appSecret       requestUrlParam.put("js_code", code); // 小程序调用wx.login返回的code       requestUrlParam.put("grant_type", "authorization_code"); // 默认参数       // 发送post请求读取调用微信 https://api.weixin.qq.com/sns/jscode2session       // 接口获取openid用户唯一标识       JSONObject jsonObject = JSON.parseObject(sendPost(requestUrl, requestUrlParam));        System.out.println(jsonObject);       return jsonObject;   }/**    * 解密用户敏感数据获取用户信息    *    * @author zhy    * @param sessionKey    *            数据进行加密签名的密钥    * @param encryptedData    *            包括敏感数据在内的完整用户信息的加密数据    * @param iv    *            加密算法的初始向量    * @return    */   public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {encryptedData=encryptedData.replace(" ", "+");       sessionKey=sessionKey.replace(" ", "+");       iv=iv.replace(" ", "+");       // 被加密的数据       byte[] dataByte = Base64.decode(encryptedData);       // 加密秘钥       byte[] keyByte = Base64.decode(sessionKey);       // 偏移量       byte[] ivByte = Base64.decode(iv);       try {// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要           int base = 16;           if (keyByte.length % base != 0){int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);               byte[] temp = new byte[groups * base];               Arrays.fill(temp, (byte) 0);               System.arraycopy(keyByte, 0, temp, 0, keyByte.length);               keyByte = temp;           }// 初始化           Security.addProvider(new BouncyCastleProvider());           Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");           SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");           AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");           parameters.init(new IvParameterSpec(ivByte));           cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化           byte[] resultByte = cipher.doFinal(dataByte);           if (null != resultByte && resultByte.length  0){String result = new String(resultByte, "UTF-8");               return JSON.parseObject(result);           }} catch (Exception e) {log.error(e.getMessage(), e);       }return null;   }/**    * 向指定 URL 发送POST方法的请求    *    * @param url    *            发送请求的 URL    * @param    *    * @return 所代表远程资源的响应结果    */   public static String sendPost(String url, MapString, ? paramMap) {PrintWriter out = null;       BufferedReader in = null;       String result = "";       String param = "";       IteratorString it = paramMap.keySet().iterator();       while (it.hasNext()) {String key = it.next();           param += key + "=" + paramMap.get(key) + "&";       }try {URL realUrl = new URL(url);           // 打开和URL之间的连接           URLConnection conn = realUrl.openConnection();           // 设置通用的请求属性           conn.setRequestProperty("accept", "*/*");           conn.setRequestProperty("connection", "Keep-Alive");           conn.setRequestProperty("Accept-Charset", "utf-8");           conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");           // 发送POST请求必须设置如下两行           conn.setDoOutput(true);           conn.setDoInput(true);           // 获取URLConnection对象对应的输出流           out = new PrintWriter(conn.getOutputStream());           // 发送请求参数           out.print(param);           // flush输出流的缓冲           out.flush();           // 定义BufferedReader输入流来读取URL的响应           in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));           String line;           while ((line = in.readLine()) != null) {result += line;           }} catch (Exception e) {log.error(e.getMessage(), e);       }// 使用finally块来关闭输出流、输入流       finally {try {if (out != null){out.close();               }if (in != null){in.close();               }} catch (IOException ex) {ex.printStackTrace();           }}return result;   }}

注解写的很明白的,应该没什么看不懂。

之后就是service层

package com.everest.academy.service.impl;import com.alibaba.fastjson.JSONObject;import com.everest.academy.business.dto.LoginUserDTO;import com.everest.academy.business.dto.WechatTokenDto;import com.everest.academy.framework.exception.ResourceIsNullException;import com.everest.academy.framework.pojo.User;import com.everest.academy.persistence.mapper.UserMapper;import com.everest.academy.service.WechatService;import com.everest.academy.util.WechatUtil;import com.everest.academy.util.XcxUtils;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.Date;/*** @ClassName WechatServiceImpl* @Description 微信sgervice* @Author 田野* @Data 20:25* @Version 1.0**/@Slf4j@Servicepublic class WechatServiceImpl implements WechatService {@Autowired   UserMapper userMapper; @Override   public LoginUserDTO getUserByCode(String code, String encryptedData, String iv)throws Exception{log.info("传进来的值"+encryptedData+"另一个"+iv);       JSONObject shopAddress = null;       if (StringUtils.isNotEmpty(code)) {String appid = "填自己的";           String secret = "填自己的";           shopAddress = XcxUtils.getSessionKeyOropenid(code, appid, secret);       }assert shopAddress != null;       String openId = shopAddress.getString("openid");       String sessionKey = shopAddress.getString("session_key");       log.info("session_key为:"+sessionKey);       JSONObject user1 = XcxUtils.getUserInfo(encryptedData, sessionKey, iv);       //user这里根据用户openId查询是否有这个用户。       User user=userMapper.findByOpenId(openId);       LoginUserDTO loginUserDTO=new LoginUserDTO();       if (user!=null){log.info("用户的状态"+user.getState());           if (user.getState()==1){//有的话,直接就进入 ,直接将信息返回给前端               loginUserDTO.setId(user.getId());               loginUserDTO.setOpenId(openId);               return loginUserDTO;           }throw new Exception("无法登录,账号被冻结");       }//没有的话,创建该学生的信息,然后再传给部分数据给前端       User newUser=new User();       newUser.setOpenId(openId);       assert user1 != null;       newUser.setAddress(user1.getString("city"));       newUser.setHeadImgUrl(user1.getString("avatarUrl"));       newUser.setName(user1.getString("nickName"));       newUser.setState(1);       newUser.setBeans(0);       newUser.setBinding(0);       newUser.setCreate_at(new Date().getTime());       newUser.setCreate_by("系统创建");       userMapper.insert(newUser);       User user2=userMapper.findByOpenId(openId);       LoginUserDTO loginUserDTO1=new LoginUserDTO();       loginUserDTO1.setId(user2.getId());       log.info("id的值"+newUser.getId());       loginUserDTO1.setOpenId(newUser.getOpenId());       loginUserDTO1.setBinding(newUser.getState());       return loginUserDTO1;   }}

也写的挺清楚的,通过openId判断是否有这个用户

controller

 

package com.everest.academy.controller;import com.everest.academy.business.vo.ResponseVo;import com.everest.academy.framework.exception.ResourceIsNullException;import com.everest.academy.service.WechatService;import com.everest.academy.util.ResultUtil;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.*;import java.util.Map;/*** @ClassName WechatController* @Description 微信登录验证* @Author 田野* @Data 15:56* @Version 1.0**/@Slf4j@Api(tags = "WechatController",description = "微信开发API")@RestController@RequestMapping("/a/home")@Validatedpublic class WechatController {@Autowired   WechatService wechatService;   @ApiOperation(value = "微信登录验证",notes = "通过获取的codeId值登录")@PostMapping("/{code}")public ResponseVo WechatLogin( @PathVariable("code") String code,                                  @RequestParam("encryptedData") String encryptedData,@RequestParam("iv") String iv)throws Exception{log.info("传进来的未"+encryptedData +"iv为" + iv);       return ResultUtil.success("微信登录成功",wechatService.getUserByCode(code,encryptedData,iv));   }}

就有一点问题

测试的时候,每次传参都读不到+号,每次都把我的+号弄掉。

所以这里运用了一个replace,完美解决

微信网页开发,通过codeId得到access_token,通过access_token和openid获取用户基本信息

package com.everest.academy.util;import com.everest.academy.business.dto.LoginUserDTO;import com.everest.academy.business.dto.WechatTokenDto;import com.google.gson.Gson;import com.google.gson.JsonObject;import lombok.extern.slf4j.Slf4j;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;import java.util.HashMap;import java.util.Map;/** * @ClassName WechatUtil * @Description TODO * @Author 田野 * @Data 19:25 * @Version 1.0 **/@Slf4jpublic class WechatUtil {    public final static String APPID = "自己的";    public final static String APPSECRET = "自己的";    /**     * 获取请求用户信息的access_token     * @param code     * @return     */    public static WechatTokenDto getUserInfoAccessToken(String code) {        JsonObject object = null;        WechatTokenDto wechatTokenDto=new WechatTokenDto();        MapString, String data = new HashMap();        try {            String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",                    APPID, APPSECRET, code);            log.info("request accessToken from url: {}", url);            CloseableHttpClient httpClient =HttpClients.createDefault();            HttpGet httpGet = new HttpGet(url);            HttpResponse httpResponse = httpClient.execute(httpGet);            HttpEntity httpEntity = httpResponse.getEntity();            String tokens = EntityUtils.toString(httpEntity, "utf-8");            Gson token_gson = new Gson();            object = token_gson.fromJson(tokens, JsonObject.class);            log.info("request accessToken success. [result={}]", object);            wechatTokenDto.setOpenid(object.get("openid").toString().replaceAll(""", ""));            wechatTokenDto.setAccess_token(object.get("access_token").toString().replaceAll(""", ""));            wechatTokenDto.setRefresh_token(object.get("refresh_token").toString().replaceAll(""", ""));            wechatTokenDto.setScope(object.get("scope").toString().replaceAll(""", ""));            wechatTokenDto.setExpires_in(Integer.parseInt(object.get("expires_in").toString().replaceAll(""","")));//            data.put("openid", object.get("openid").toString().replaceAll(""", ""));//            data.put("access_token", object.get("access_token").toString().replaceAll(""", ""));//            data.put("expires_in",object.get("expires_in").toString().replaceAll(""",""));//            data.put("refresh_token",object.get("refresh_token").toString().replaceAll(""", ""));//            data.put("scope",object.get("scope").toString().replaceAll(""", ""));        } catch (Exception ex) {            log.error("fail to request wechat access token. [error={}]", ex);        }        return wechatTokenDto;    }    /**     * 通过access_token和openid获取用户基本信息     * @param accessToken     * @param openId     * @return     */    public static LoginUserDTO getUserInfo(String accessToken, String openId) {        LoginUserDTO loginUserDTO=new LoginUserDTO();        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";        log.info("request user info from url: {}", url);        JsonObject userInfo = null;        try {            CloseableHttpClient httpClient =HttpClients.createDefault();            HttpGet httpGet = new HttpGet(url);            HttpResponse httpResponse = httpClient.execute(httpGet);            HttpEntity httpEntity = httpResponse.getEntity();            String response = EntityUtils.toString(httpEntity, "utf-8");            Gson token_gson = new Gson();            userInfo = token_gson.fromJson(response, JsonObject.class);            log.info("get userinfo success. [result={}]", userInfo);            loginUserDTO.setOpenId(userInfo.get("openid").toString().replaceAll(""", ""));            loginUserDTO.setCountry(userInfo.get("country").toString().replaceAll(""", ""));            loginUserDTO.setProvince(userInfo.get("province").toString().replaceAll(""", ""));            loginUserDTO.setCity(userInfo.get("city").toString().replaceAll(""", ""));            loginUserDTO.setHeadImgUrl(userInfo.get("headimgurl").toString().replaceAll(""", ""));            loginUserDTO.setSex(Integer.valueOf(userInfo.get("sex").toString().replaceAll(""", "")));            loginUserDTO.setNickname(userInfo.get("nickname").toString().replaceAll(""", ""));//            data.put("openid", userInfo.get("openid").toString().replaceAll(""", ""));//            data.put("nickname", userInfo.get("nickname").toString().replaceAll(""", ""));//            data.put("city", userInfo.get("city").toString().replaceAll(""", ""));//            data.put("province", userInfo.get("province").toString().replaceAll(""", ""));//            data.put("country", userInfo.get("country").toString().replaceAll(""", ""));//            data.put("headimgurl", userInfo.get("headimgurl").toString().replaceAll(""", ""));        } catch (Exception ex) {            log.error("fail to request wechat user info. [error={}]", ex);        }        return loginUserDTO;    }}
@Override    public LoginUserDTO wechat(String code)throws ResourceIsNullException{        //调用封装的微信方法,通过code值得到wechatTokenDto        WechatTokenDto wechatTokenDto=WechatUtil.getUserInfoAccessToken(code);        String accessToken = wechatTokenDto.getAccess_token();//得到accessToken        String openId = wechatTokenDto.getOpenid();//得到openId        //user这里根据用户openId查询是否有这个用户。        User user=userMapper.findByOpenId(openId);        LoginUserDTO loginUserDTO=WechatUtil.getUserInfo(accessToken,openId);        log.info("用户信息"+user);        if(user!=null){            //有的话,直接就进入 ,直接将信息返回给前端//            loginUserDTO.setOpenId(openId);            loginUserDTO.setId(user.getId());            loginUserDTO.setBinding(user.getState());            return loginUserDTO;        }else {            //没有的话,创建该学生的信息,然后再传给部分数据给前端            User newUser=new User();            newUser.setOpenId(loginUserDTO.getOpenId());            newUser.setAddress(loginUserDTO.getCity());            newUser.setHeadImgUrl(loginUserDTO.getHeadImgUrl());            newUser.setName(loginUserDTO.getNickname());            log.info("用户昵称"+loginUserDTO.getNickname());            newUser.setState(1);            newUser.setBeans(0);            newUser.setBinding(0);            newUser.setCreate_at(new Date().getTime());            newUser.setCreate_by("系统创建");            userMapper.insert(newUser);            LoginUserDTO loginUserDTO1=new LoginUserDTO();            loginUserDTO1.setId(newUser.getId());            log.info("id的值"+newUser.getId());            loginUserDTO1.setOpenId(newUser.getOpenId());            loginUserDTO1.setBinding(newUser.getState());            return loginUserDTO1;        }    }

基本就是这个样子,后续看下能不能写的更加详细。

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎