前端实现代码

// 登录
	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三大参数

java 获取微信token java微信授权获取openid原理_openid


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);
        conn.connect();
        StringBuffer buffer = new StringBuffer();
        // 将返回的输入流转换成字符串
        String result;
        try (InputStream inputStream = conn.getInputStream();
             InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
             BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            result = buffer.toString();
        }
        return JSONObject.parseObject(result);
    }
}

测试

java 获取微信token java微信授权获取openid原理_java_02


java 获取微信token java微信授权获取openid原理_java_03


可以看到我们成功获取到了openid以及用户的一些信息,完美搞定~

需要注意的地方

1、前后台的appid与secret必须一致!!!否则会解析失败!2、三大参数只能使用一次,使用过之后需要重新获取新的!

pom文件

<!-- 依赖声明 -->
    <dependencies>
        <!--SpringBoot Web容器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--SpringBoot 拦截器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
        <!-- swagger2-UI-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!--io常用工具类 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>
        <!-- 阿里JSON解析器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.74</version>
        </dependency>
        <!--lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.59</version>
        </dependency>
    </dependencies>

写在最后

谢谢你的点击与阅读,如果文章对你有帮助的话,请动动您发财的小手点个小赞、收藏或者关注博主一下,谢谢!一心原创,为了后人乘凉。