当前位置 博文首页 > 谢哥哥的博客:【微信开发相关】Java后端微信授权登录,获取微信

    谢哥哥的博客:【微信开发相关】Java后端微信授权登录,获取微信

    作者:[db:作者] 时间:2021-07-13 13:11

    前端实现代码

    	// 登录
    	wx.login({
    	  success: function (res) {
    	      if (res.code) {
    	          // 3获取用户信息 encryptedData iv 解密出 unionId
    	          wx.getUserInfo({
    	              success: function (respon) {
    	                console.log("encryptedData:" + respon.encryptedData);
    	                console.log("iv:" + respon.iv);
    	                console.log("code:" + res.code);
    	              }
    	          })
    	      } else {
    	          console.log('获取用户登录态code失败' + res.errMsg)
    	          wx.hideLoading()
    	      }
    	  }
    	})
    

    需要前端用户授权拿到encryptedData、iv、code三大参数
    在这里插入图片描述
    encryptedData:用户的加密秘钥
    iv:偏移量
    code:微信生成当前的唯一标识

    后端实现代码

    import com.alibaba.fastjson.JSONObject;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.encoders.Base64;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    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.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.nio.charset.StandardCharsets;
    import java.security.AlgorithmParameters;
    import java.security.Security;
    import java.util.Arrays;
    
    /**
     * @author xiegege
     * @date 2021/3/2 11:16
     */
    @RequestMapping("/wechat/login")
    @RestController
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    @Slf4j
    public class WechatLoginController {
    
        private static final String APP_ID = "你的appId";
        private static final String SECRET = "你的secret";
    
        @ApiOperation(value = "微信授权登录")
        @PostMapping("wechat-login")
        public String wechatLogin(String encryptedData, String iv, String code) {
            String errMsg = "解析失败!";
            try {
                String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + APP_ID + "&secret=" + SECRET + "&js_code=" + code + "&grant_type=authorization_code";
                JSONObject res = getJsonObject(url);
                log.info("res: " + res);
                if (res == null) {
                    return errMsg;
                }
                if (res.get("errcode") != null) {
                    return errMsg;
                }
                // 获取openid
                String openid = res.getString("openid");
                log.info("openid:" + openid);
                // 根据微信openid查询用户,如果有查到用户数据则生成token登录。如果没有查询到用户数据则新增一条用户,并把openid存入
                // 解析用户信息
                JSONObject res1 = getUserInfo(encryptedData, String.valueOf(res.get("session_key")), iv);
                if (res1 == null) {
                    return errMsg;
                }
                // todo:通过openid查找用户信息
                /*WeChatUser user = userService.findUserByOpenId(openid);
                if (user == null) {
                    // 新增用户
    
                } else {
                    // 用户存在,更新用户信息,如昵称、头像、性别等...
    
                }*/
                log.info("昵称:" + res1.getString("nickName"));
                log.info("头像:" + res1.getString("avatarUrl"));
                log.info("性别:" + res1.getByte("gender"));
    
                return "openid:" + openid;
            } catch (Exception e) {
                e.printStackTrace();
                return errMsg;
            }
        }
    
        /**
         * 解密用户敏感数据获取用户信息
         *
         * @param sessionKey    数据进行加密签名的密钥
         * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
         * @param iv            加密算法的初始向量
         */
        public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
            // 被加密的数据
            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, StandardCharsets.UTF_8);
                    return JSONObject.parseObject(result);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private JSONObject getJsonObject(String url) throws IOException {
            URL serverUrl = new URL(url);
            HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Content-type", "application/json");
            // 必须设置false,否则会自动redirect到重定向后的地址
            conn.setInstanceFollowRedirects(false);