微信开发:第三方网站微信登录实现
安安 2017-08-24 来源 :网络 阅读 844 评论 0

摘要:本篇文章为大家介绍微信开发中第三方网站微信登录实现,看完这篇文章会让你对微信开发的知识点有更加清晰的理解和运用。

本篇文章为大家介绍微信开发中第三方网站微信登录实现,看完这篇文章会让你对微信开发的知识点有更加清晰的理解和运用。

 

 好记性不如烂笔头!且 coding 且记下^^

  前两个星期在公司中的项目加上了微信登录、绑定的功能,在这里做个记录!

一、开发前知识

  1、微信开放平台与微信公众平台的区别

    1.1 微信公众平台:  

    ① 地址:  https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CN

    ② 微信公众平台面向的是普通的用户,比如自媒体和媒体,企业官方微信公众账号运营人员使用,当然你所在的团队或者公司有实力去开发一些内容,也可以调用公众平台里面的接口,比如自定义菜单,自动回复,查询功能。

    1.2 微信开放平台:  

    ① 地址:  https://open.weixin.qq.com/

    微信开放平台:面向的是开发者和第三方独立软件开发商。开放平台的文档似乎包含了微信开放平台文档里面的接口。

  2、微信公众平台目前只支持80端口,且项目上传到服务器上面不容易debug啊?

    解决方法: ngrok 工具,可以根据本地项目映射成外网可以访问的地址、端口,默认映射为80端口。

      官网:       https://dashboard.ngrok.com

      存在问题: 每次重启,域名会变化,都需要项目中、微信公众平台配置,付费可以固定域名。。。

    使用方法: ① 注册后获得一个授权码,下载 ngrok

          ② 》CMD 进入 ngrok 目录

            》ngrok authtoken 授权码

            》ngrok http 8080

         ③看到这个页面,ngrok就为你分配了临时访问通道成功了^^

 

微信开发:第三方网站微信登录实现 

二、配置

  (每个微信号可以申请成为开发者测试账号进行微信功能开发的。)

  1、在公众平台中进行配置:

    地址: //mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

    ①:配 置 “接口配置信息” (Token 在项目中我是配置为"handsomeKing",没错,我就是King ^^)

      url 改为自己映射的域名

 微信开发:第三方网站微信登录实现

    ② 配 置“功能服务” 的 “网页帐号”。注意,是域名

微信开发:第三方网站微信登录实现 

  好了,可以愉快的 coding 了!!!

三、可以开发啦

    1、上面的 “接口配置信息” 配置得 wechat/ownerCheck 方法是验证 这个url 为我自己的,handsomeKing 就是这个方法中的一个参数。微信这个小朋友会用Get方法带上4个参数给我服务器: signature(签名)、timestamp(时间戳)、nonce(随机数)、echostr(随机字符串),再加上咱们项目中自己配置的 token ,通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败:(talk is cheap, show me the code *&)

 

 /**

     * 微信消息接收和token验证

     * @param model

     * @param request

     * @param response

     * @throws IOException

     */

    @RequestMapping("/ownerCheck")

    public void ownerCheck(Model model, HttpServletRequest request,HttpServletResponse response) throws IOException {

        System.out.println(111);

        boolean isGet = request.getMethod().toLowerCase().equals("get");

        PrintWriter print;

        if (isGet) {

            // 微信加密签名

            String signature = request.getParameter("signature");

            // 时间戳

            String timestamp = request.getParameter("timestamp");

            // 随机数

            String nonce = request.getParameter("nonce");

            // 随机字符串

            String echostr = request.getParameter("echostr");

            // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败

            if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {

                try {

                    print = response.getWriter();

                    print.write(echostr);

                    print.flush();

                } catch (IOException e) {

                    e.printStackTrace();

                }

            }

        }

    }

 

 

import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;

public class CheckoutUtil {

    // 与接口配置信息中的Token要一致

    private static String token = "handsomeKing";

 

    /**

     * 验证签名

     *

     * @param signature

     * @param timestamp

     * @param nonce

     * @return

     */

    public static boolean checkSignature(String signature, String timestamp, String nonce) {

        String[] arr = new String[] { token, timestamp, nonce };

        // 将token、timestamp、nonce三个参数进行字典序排序

        // Arrays.sort(arr);        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对比,标识该请求来源于微信

        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;

    }

    public static void sort(String a[]) {

        for (int i = 0; i < a.length - 1; i++) {

            for (int j = i + 1; j < a.length; j++) {

                if (a[j].compareTo(a[i]) < 0) {

                    String temp = a[i];

                    a[i] = a[j];

                    a[j] = temp;

                }

            }

        }

    }

}

 

2、用户用户同意授权,获取微信服务器传过来的俩参数: code、state。其中:

APPID: 微信开发者测试账号

REDIRECT_URI: 同意授权后跳转的 URL

 

/**

     * 第一步:用户同意授权,获取code(引导关注者打开如下页面:)

     *  获取 code、state

     */

    public static String getStartURLToGetCode() {

        

        String takenUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";

        takenUrl= takenUrl.replace("APPID", Param.APPID);

        takenUrl= takenUrl.replace("REDIRECT_URI", URL.encode(Param.REDIRECT_URI));

        //FIXME : snsapi_userinfo

        takenUrl= takenUrl.replace("SCOPE", "snsapi_userinfo");

        System.out.println(takenUrl);

        return takenUrl;

    }

 

3、获取微信用户的 access_token、openid

APPID: 微信开发者测试账号
secret: 微信开发者测试账号密码
code:  上一步的 code

 

/**

     * 获取access_token、openid

     * 第二步:通过code获取access_token

     * @param code url = "https://api.weixin.qq.com/sns/oauth2/access_token

     *                      ?appid=APPID

     *                      &secret=SECRET

     *                      &code=CODE

     *                      &grant_type=authorization_code"

     * */

    public static OAuthInfo getAccess_token(String code){

        

     

        String authUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code ";

        authUrl= authUrl.replace("APPID", Param.APPID);

        authUrl = authUrl.replace("SECRET", Param.SECRET);

        authUrl = authUrl.replace("CODE", code);

        String jsonString = HTTPRequestUtil.sendPost(authUrl,"");

        System.out.println("jsonString: " + jsonString);

        OAuthInfo auth = null;

        try {

            auth = (OAuthInfo) JacksonUtil.parseJSONToObject(OAuthInfo.class, jsonString);

        } catch (Exception e) {

            e.printStackTrace();

        }

        return auth;

    }

    

 

 

4、在数据库中查询 openid

  我是定义了一个对象 OauthInfo,包括 openid(用户的标识)属性。。。

  查询时库中存在就直接登录啦,不存在就先去登录页,将登录账号同 openid 绑定。

 

/**

     * 微信引导页进入的方法

     * @return

     */

    @RequestMapping("/loginByWeiXin")

    public String loginByWeiXin(HttpServletRequest request, Map<String, Object> map) {

        // 微信接口自带 2 个参数

        String code = request.getParameter("code");

        String state = request.getParameter("state");

        System.out.println("code = " + code + ", state = " + state);

        

        if(code != null && !"".equals(code)) {

            // 授权成功, 微信获取用户openID

            OAuthInfo authInfo = WeiXinUtil.getAccess_token(code);

            String openid = authInfo.getOpenid();

            String access_token = authInfo.getAccess_token();

            

            if(access_token == null) {

                // Code 使用过 异常

                System.out.println("Code 使用过 异常.....");

                return "redirect:" + WeiXinUtil.getStartURLToGetCode();

            }

            

            // 数据库中查询微信号是否绑定平台账号

            SysUser sysUser = weiXinService.getUserByWeiXinID(openid);

            if(sysUser == null) {

                String randomStr = StringUtil.getRandomString(50);

                request.getSession().setAttribute(openid, randomStr);

                // 尚未绑定账号

                System.out.println("尚未绑定账号.....");

                return "redirect:/index.jsp?openid=" + openid + "&state=" + randomStr;

            }

            userController.doSomeLoginWorkToHomePage(sysUser.getMcid(), map);

            // 登录成功

            return "homePage";

        }

        // 未授权

        return "redirect:" + WeiXinUtil.getStartURLToGetCode();

    

    }

 

四、踩过的坑

  1、access_token 与 普通 access_token。这尼玛是啥关系?

   答:access_token: 登录授权会得到一个 access_token, 这个是用于标识登录用户(没有使用次数限制),绑定流程中用的都是 登录 access_token。

      普通 access_token:   调用其它微信应用接口时需要带上的 access_token,普通 access_token时效为 2H, 每个应用每天调用次数<= 2000次。(实际开发时必须加以处理。。我采用的是 quartz 调度^^)

  2、 uuid、openid。我该绑定uuid?不不不,openid?不不,到底绑哪个?

     答:uuid: 微信号绑定后才有的标识,对于任何应用该微信账号的 uuid 均相同。同一个微信账号不同的应用 uuid 相同。

       openid: 微信号对于每个应用均有一个不变的 openid,同一个微信账号不同的应用 openid 不同。 

五、参考的链接!感谢!!

    //blog.csdn.net/zhaojiacan/article/details/51024944

  文中也许会存在我理解上的错误,望各位不吝赐教,小弟定会加以改正^^


    希望这篇微信开发文章可以帮助到你。总之,同学们,你想要的职坐标微信开发频道都能找到!

本文由 @安安 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程