java实现微信登录

参考链接:https://blog.csdn.net/chmod_r_755/article/details/75554735


最近项目有微信登录的功能,在token验证的位置出了一些问题,我这里使用的是微信测试号。

首先是微信测试号的配置:

这里的token随便写什么都可以,唯一需要注意的就是要和后台使用的一致。

url必须是公网的地址,微信会发一些数据来测试这个接口,这个时候你需要在后台接受这个数据并且把数据返回,才能通过测试。

下面是controller的代码:

 @GetMapping("/wx/wxLogin")
    public void doWxLogin (HttpServletRequest request, HttpServletResponse response) {

        try {
            userService.doWxLogin(request, response);
        } catch (Exception e) {
            e.printStackTrace();
            //相应的处理
        }

    }

下面是service的代码:

@Override
    public void doWxLogin(HttpServletRequest request, HttpServletResponse response) throws IOException{

        String authUrl = WxConstants.AUTH_BASE_URL + "appid=" + WxConstants.APPID
                + "&redirect_uri=" + URLEncoder.encode(WxConstants.REDIRECT_URL)
                + "&response_type=code"
                + "&scope=" + WxConstants.SCOPE
                + "&state=STATE#wechat_redirect";


        String signature = request.getParameter("signature");/// 微信加密签名
        String timestamp = request.getParameter("timestamp");/// 时间戳
        String nonce = request.getParameter("nonce"); /// 随机数
        String echostr = request.getParameter("echostr"); // 随机字符串

        PrintWriter out = response.getWriter();

        if (signature != null && timestamp != null && nonce != null && echostr != null) {
            if (SignUtil.checkSignature(signature, timestamp, nonce)) {
                out.print(echostr);
            }
            out.close();
        } else {
            response.sendRedirect(authUrl);
        }
    }    

    service中获取到微信发来的四个参数,并且调用SignUtil的方法进行token的验证,如果已经通过验证就直接使用拼装好的url发送授权请求(这里需要使用到自己的APPID)。

SignUtil方法如下:


public class SignUtil {

    private static final String token = WxConstants.TOKEN;

    /**
     * 校验签名
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        System.out.println("signature:" + signature + "timestamp:" + timestamp + "nonc:" + nonce);
        String[] arr = new String[] { token, timestamp, nonce };
        // 将token、timestamp、nonce三个参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        System.out.println(tmpStr.equals(signature.toUpperCase()));
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 将字节数组转换为十六进制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * 将字节转换为十六进制字符串
     *
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }
}

通过token验证后,就可以执行微信授权操作,下面是授权回调的代码:

public RecycleResult doWxCallBack(String code, HttpServletRequest request, HttpServletResponse response) throws  Exception{

        //通过code换取网页授权access_token
        String access_token_url = WxConstants.ACCESS_TOKEN_BASE_URL
                + "appid=" + WxConstants.APPID
                + "&secret=" + WxConstants.APPSECRET
                + "&code=" + code
                + "&grant_type=authorization_code";

        //发送请求
        String jsonResult = HttpClientUtil.doGet(access_token_url);
        if (jsonResult == null || "".equals(jsonResult)) {
            logger.debug("认证失败");
            return RecycleResult.build(500, "认证失败");
        }

        JsonObject accessJsonObject = new JsonParser().parse(jsonResult).getAsJsonObject();

        //与开放平台关联要使用unionid
        String openid = accessJsonObject.get("openid").getAsString();
        String access_token = accessJsonObject.get("access_token").getAsString();

        /**
         * 微信与用户信息的绑定
         */
        User user = userMapper.getUserInfoByOpenid(openid);
        if (user == null) {
            logger.debug("请先登录进行授权");
            //先登录,然后执行绑定授权操作
            return RecycleResult.build(401, "请先登录进行授权", openid);
        }

        /**
         * 获取用户的微信信息(需scope为 snsapi_userinfo)
         */
        String infoUrl = WxConstants.INFO_BASE_URL
                + "access_token=" + access_token
                + "&openid=" + openid
                + "&lang=zh_CN";
        String userInfoJson = HttpClientUtil.doGet(infoUrl);
        if (userInfoJson == null || "".equals(userInfoJson)) {
            logger.debug("获取用户微信信息失败");
            return RecycleResult.build(500, "获取用户微信信息失败");
        }

        //使用微信的信息
        JsonObject userInfoJsonObject = new JsonParser().parse(userInfoJson).getAsJsonObject();

        //返回用户信息
        List infoList = new ArrayList<>();
        infoList.add(userInfoJsonObject);
        infoList.add(user);

        //保存用户信息
        userInfoMap.put(user.getUsername(), infoList);
 
        return RecycleResult.ok(user.getUsername());
    }

    在访问授权的URL时,微信会返回一个code,使用code、APPID、APPSECRET换取access_token,授权通过。

上面代码中使用到的Wxconstants是笔者自己封装的一个常量类,


总结:

    其实微信授权登录,就是把微信提供的一个openid(如果需要和微信开放平台整合则需要使用unionid)保存下来,这个openid来获取微信的或者是数据库中的信息,从而可以获取信息。


  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值