• 微信公众号授权


    首次学习参考网址:https://blog.csdn.net/kelly921011/article/details/97776226

    微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html

    我们需要有一个测试账号,可以用微信提供的测试账号

     1、点击此链接,用微信扫描二维码,申请测试账号

     这样就获取到了测试账号的appId、appsecret

    2、添加用户

    扫描此二维码,添加用户

    3、配置重定向url地址

     4、配置js接口安全域名

     公众号基本信息配置好以后,下面就是按照要求,写代码了

     配置文件application.properties

     wechat.redirect.url=http://192.168.7.101:8080      (此处与公众号里配置的网页授权url地址一致)

    1、用户同意授权获取code

    controller层:

    @RequestMapping(value = "/get-url", method = RequestMethod.GET)
    public JSONObject getUrl(WechatDTO wechatDTO) {
        return weChatService.getUrl(wechatDTO);
    }

    service层 WeChatServiceImpl
    @Value("${wechat.appid}")
    private String wechatAppId;

    @Value("${wechat.secret}")
    private String wechatAppSecret;

    @Value("${wechat.redirect.host}")
    private String redirectHost;

    @Value("${wechat.user.html}")
    private String userHtml;

    @Value("${wechat.engineer.html}")
    private String engineerHtml;


    /*** 获取授权登录重定向url
    * @return JSONObject
    * @throws BusinessException
    */
    public JSONObject getUrl(WechatDTO wechatDTO) throws BusinessException {
        logger.debug("进入了getUrl方法");
    try {
        String html = "";
        if ("1".equals(type)) {
         html = userHtml;
        } else if ("2".equals(type)) {
         html = engineerHtml;
        }
        redirectHost = redirectHost + html;
            String redirectUri = URLEncoder.encode(redirectUrl, "UTF-8");
    String url = String.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo#wechat_redirect", wechatAppId, redirectUri, wechatAppSecret);
    JSONObject result = new JSONObject();
    result.put("url", url);
    return result;
    } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }

    postman测试此接口,并返回url

    2、通过code获取网页授权token        (实际项目中wechat.engineer.html里写此接口,通过这个页面调用此接口)

    由于是自己后台测试,我用的方法是,把获取的这个url,发到我自己的微信号,之后点此链接,获取token

    controller层代码

    /**
    * @api {get} /wechat/get-access-token-by-code 根据code获取token
    * @apiPermission none
    * @apiName get-access-token-by-code
    * @apiGroup wechat
    * @apiDescription 根据code获取token
    * @apiParam {String} code code
    * @apiParam {String} [param2] 参数2
    * @apiParamExample {json} 参数示例:
    * {
    * <p>
    * }
    * @apiSuccess {String} access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
    * @apiSuccess {String} expires_in access_token接口调用凭证超时时间,单位(秒)
    * @apiSuccess {String} refresh_token 用户刷新access_token
    * @apiSuccess {String} openid 用户唯一标识,请注意,在未关注公众号时,用户访问公众号的网页,也会产生一个用户和公众号唯一的OpenID
    * @apiSuccess {String} scope 用户授权的作用域,使用逗号(,)分隔
    * @apiSuccessExample {json} 返回示例:
    * HTTP/1.1 200 OK
    * {
    * "access_token":"ACCESS_TOKEN",
    * "expires_in":7200,
    * "refresh_token":"REFRESH_TOKEN",
    * "openid":"OPENID",
    * "scope":"SCOPE"
    * }
    */
    @RequestMapping(value = "/get-access-token-by-code", method = RequestMethod.GET)
    public JSONObject getAccessTokenByCode(WechatDTO wechatDTO) {
    return weChatService.getAccessTokenByCode(wechatDTO);
    }

    service层
    /*** 通过code换取网页授权access_token
    * @return JSONObject
    * @throws BusinessException
    */
    public JSONObject getAccessTokenByCode(WechatDTO wechatDTO) throws BusinessException {
        logger.debug("进入了getAccessTokenByCode方法");
    try {
        String code = wechatDTO.getCode();
        String access_token = wechatDTO.getAccess_token();
        String openid = wechatDTO.getOpenid();
        String refresh_token = wechatDTO.getRefresh_token();
        if (StringUtils.isBlank(code)) {
        throw new BusinessException("code不能为空", 400, null);
        }
        if (StringUtils.isNotBlank(access_token) && StringUtils.isNotBlank(openid) && StringUtils.isNotBlank(refresh_token)) {
          // 校验token是否过期
        JSONObject validTokenJson = this.validAccessToken(wechatDTO);
        if (!"0".equals(validTokenJson.getString("errcode"))) {
          // 刷新token
       return this.getAccessTokenByRefreshToken(wechatDTO);
       }
        }
        // 第一次授权登录
        JSONObject tokenObject = new JSONObject();
        String result = HttpClientUtils.executeByGET(String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", wechatAppId, wechatAppSecret, code));
        if (StringUtils.isNotBlank(result)) {
        tokenObject = JSONObject.parseObject(result);
        }
        return tokenObject;
        } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }
    /*** 检验授权凭证(access_token)是否有效
    * @param wechatDto 微信dto
    * @return JSONObject
    * @throws BusinessException
    */
    public JSONObject validAccessToken(WechatDTO wechatDto) throws BusinessException {
    logger.debug("进入了validAccessToken方法");
    try {
    String access_token = wechatDto.getAccess_token();
    String openid = wechatDto.getOpenid();
    String url = String.format("https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s", access_token, openid);
    String result = HttpClientUtils.executeByGET(url);
    JSONObject userinfo = new JSONObject();
    if (StringUtils.isNotBlank(result)) {
    userinfo = JSONObject.parseObject(result);
    } else {
    throw new BusinessException("检验授权凭证(access_token)是否有效失败", 400, null);
    }
    return userinfo;
    } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }
    /*** 根据refresh_token刷新access_token
    * @param wechatDTO wechatDTO
    * @return JSONObject
    * @throws BusinessException
    */
    public JSONObject getAccessTokenByRefreshToken(WechatDTO wechatDTO) throws BusinessException {
    logger.debug("进入了getAccessTokenByRefreshToken方法");
    try {
    String refreshToken = wechatDTO.getRefresh_token();
    if (StringUtils.isBlank(refreshToken)) {
    throw new BusinessException("refresh_token不能为空", 400, null);
    }

    JSONObject tokenObject = new JSONObject();
    String result = HttpClientUtils.executeByGET(String.format("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=refresh_token&refresh_token=%s", wechatAppId, refreshToken));
    if (StringUtils.isNotBlank(result)) {
    tokenObject = JSONObject.parseObject(result);
    } else {
    throw new BusinessException("刷新access_token失败", 400, null);
    }
    return tokenObject;
    } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }

     5、拉取用户信息(需scope为 snsapi_userinfo)

    controller层

    /**
    * @api {get} /wechat/get-user-info 获取用户信息
    * @apiPermission none
    * @apiName get-user-info
    * @apiGroup wechat
    * @apiDescription 获取用户信息
    * @apiParam {String} access_token 网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
    * @apiParam {String} openid 用户的唯一标识
    * @apiParam {String} [lang] 返回国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语
    * @apiParamExample {json} 参数示例:
    * {
    * <p>
    * }
    * @apiSuccess {String} openid 用户的唯一标识
    * @apiSuccess {String} nickname 用户昵称
    * @apiSuccess {String} sex 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
    * @apiSuccess {String} province 用户个人资料填写的省份
    * @apiSuccess {String} city 普通用户个人资料填写的城市
    * @apiSuccess {String} country 国家,如中国为CN
    * @apiSuccess {String} headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
    * @apiSuccess {String} privilege 用户特权信息,json 数组,如微信沃卡用户为(chinaunicom)
    * @apiSuccess {String} [unionid] 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
    * @apiSuccessExample {json} 返回示例:
    * HTTP/1.1 200 OK
    * {
    * "openid":" OPENID",
    * "nickname": NICKNAME,
    * "sex":"1",
    * "province":"PROVINCE",
    * "city":"CITY",
    * "country":"COUNTRY",
    * "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
    * "privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
    * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    * }
    */
    @RequestMapping(value = "/get-user-info", method = RequestMethod.GET)
    public JSONObject getUserInfo(WechatDTO wechatDTO) {
    return weChatService.getUserInfo(wechatDTO);
    }

    service层
    /*** 获取用户信息
    * @param wechatDto 微信dto
    * @return JSONObject
    * @throws BusinessException
    */
    public JSONObject getUserInfo(WechatDTO wechatDto) throws BusinessException {
    logger.debug("进入了getUserInfo方法");
    try {
    this.valid(wechatDto).valid("access_token", "access_token", ValidationType.BLANK)
    .valid("openid", "openid", ValidationType.BLANK);

    String access_token = wechatDto.getAccess_token();
    String openid = wechatDto.getOpenid();
    String lang = wechatDto.getLang();
    if (StringUtils.isBlank(lang)) {
    lang = "zh_CN";
    }
    String url = String.format("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s", access_token, openid, lang);
    String result = HttpClientUtils.executeByGET(url);
         // 解决中文乱码问题
    result = new String(result.getBytes("ISO-8859-1"), "UTF-8");
    JSONObject userinfo = new JSONObject();
    if (StringUtils.isNotBlank(result)) {
    userinfo = JSONObject.parseObject(result);

          // 处理emoji表情方式有如下三种:1、把表情替换成(表情) 2、把表情转换URLEncoder.encode(userinfo .getString("nickname"), "UTF-8") ,读取的时候在转换回来URLDecoder.decode(userinfo .getString("nickname"), "UTF-8")
           3、设置数据库,数据库表设置
           
           // emoji表情处理 
           Pattern emoji = Pattern.compile("[ud83cudc00-ud83cudfff]|[ud83dudc00-ud83dudfff]|[u2600-u27ff]",
             Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
          Matcher emojiMatcher = emoji.matcher(
    userinfo .getString("nickname"));
          if (emojiMatcher.find()) {
           //将所获取的表情转换为表情
           userDTO.setUserName(emojiMatcher.replaceAll("(表情)"));
          }
            } else {
    throw new BusinessException("获取微信用户个人信息失败", 400, null);
    }
    return userinfo;
    } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }

    private UserDTO userinfo(JSONObject info) {
    UserDTO userDTO = new UserDTO();
    userDTO.setWxOpenid(info.getString("openid"));
    userDTO.setUserName(info.getString("nickname"));
    return userDTO;
    }

    postmant测试

    以上就是微信公众号授权代码

    获取jsapi_ticket

    controller层

    /**
    * @api {get} /wechat/get-jsapi-ticket 获取jsapi_ticket
    * @apiPermission none
    * @apiName get-jsapi-ticket
    * @apiGroup wechat
    * @apiDescription 获取jsapi_ticket
    * @apiParam {String} url url(当前网页的URL)
    * @apiParamExample {json} 参数示例:
    * {
    * <p>
    * }
    * @apiSuccessExample {json} 返回示例:
    * HTTP/1.1 200 OK
    * {
    * "signature": "5714493857bae8c0a10bf042760147a16426bed1",
    * "appId": "wxd7cd6846d8f5c913",
    * "nonceStr": "2acb0ab89cc646c1bb9c0684a83f03d4",
    * "timestamp": 1608167304690
    * }
    */
    @RequestMapping(value = "/get-jsapi-ticket", method = RequestMethod.GET)
    public JSONObject getJsapiTicket(WechatDTO wechatDTO) {
    return weChatService.getJsapiTicket(wechatDTO);
    }

    service层

    /*** 获取jsapi_ticket
    * @return void
    * @throws BusinessException
    */
    public JSONObject getJsapiTicket(WechatDTO wechatDTO) throws BusinessException {
    logger.debug("进入了getJsapiTicket方法");
    try {
    String url = wechatDTO.getUrl();
    if (StringUtils.isBlank(url)) {
    throw new BusinessException("url不能为空", 400, null);
    }
         // 由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket (此处放到了redis缓存里)
    String cacheTicket = (String) this.getCacheService().get("WECHAT:JSAPI:TICKET");
    if (StringUtils.isBlank(cacheTicket)) {
            // 获取access_token
    String tokenString = HttpClientUtils.executeByGET(String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", wechatAppId, wechatAppSecret));
    if (StringUtils.isNotBlank(tokenString)) {
    String token = JSONObject.parseObject(tokenString).getString("access_token");
    String ticketString = HttpClientUtils.executeByGET(String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", token));
    if (StringUtils.isNotBlank(ticketString)) {
    cacheTicket = JSONObject.parseObject(ticketString).getString("ticket");
    // 此ticket在微信中有效期7200秒
    this.getCacheService().set("WECHAT:JSAPI:TICKET", cacheTicket, 7195 * 1000);
    }
    }
    }
    return this.getSign(cacheTicket, url);
    } catch (Exception ex) {
    if (ex instanceof BusinessException) {
    throw new BusinessException(ex);
    } else {
    logger.error(ex.getMessage());
    throw new BusinessException("数据异常:" + ex.getMessage(), 500, null);
    }
    }
    }

    /**
    * 获取签名
    * @param ticket
    * @param url
    * @return
    */
    private JSONObject getSign(String ticket, String url) {
    String nonce = UUIDUtils.createId_32();
    Long timestamp = System.currentTimeMillis();
    String temp = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", ticket, nonce, timestamp, url);
    String signature = DigestUtils.sha1Hex(temp);
    JSONObject result = new JSONObject();
    result.put("appId", wechatAppId);
    result.put("timestamp", timestamp);
    result.put("nonceStr", nonce);
    result.put("signature", signature);
    return result;
    }

    ******url为完成的路径

     

    jar包依赖

    HttpClientUtils.executeByGET这个方法代码如下:
    HttpClient httpclient = getHttpClient();
    HttpGet get = new HttpGet(url);

    String responseJson = (String)httpclient.execute(get, responseHandler);
    private static HttpClient httpClient = null;
    public static HttpClient getHttpClient() {
    if (httpClient == null) {
    httpClient = new DefaultHttpClient(new ThreadSafeClientConnManager());
    }

    return httpClient;
    }
  • 相关阅读:
    关于Windows程序设计的初步认识
    C++虚函数作用原理(二)——类的继承
    史诗级Java资源大全中文版
    马上加薪!测试,你的职业发展...
    你不知道的接口自动化测试!
    69道Spring面试题和答案,简单明了无套路
    大厂都在问的多线程面试题,你不了解下嘛?
    现代Java进阶之路必备技能——2019 版
    80后程序员降薪6K,预感中年危机来袭,准备跳槽却碰壁
    微服务、分布式、高并发都不懂,你拿什么去跳槽?
  • 原文地址:https://www.cnblogs.com/ssk913/p/14173185.html
Copyright © 2020-2023  润新知