SpringCloud : 接入 微信公众号平台(二)、菜单跳转auth2.0授权

 

大概流程:

1. 通过 https://域名/auth/getOauthUrl 获取到auth2.0的授权跳转地址(也就是微信公众号跳转菜单绑定的链接)。

如何添加菜单请参考代码:WxMenuController.java

核心代码就是 wxMpService.oauth2buildAuthorizationUrl("处理授权回调的url", WxConsts.OAuth2Scope.SNSAPI_USERINFO, this.urlEncode("目标链接"));

 

2. 然后访问该链接,微信为弹出一个确认授权弹窗,用户确认通过之后,会跳转到 https://域名/auth/callback 处理微信授权回调。 

 

 

3. 然后callback 方法处理完毕后,再重定向到你需要重定向的目标链接。

 

import com.phpdragon.wechat.proxy.config.WeChatConfig;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.view.RedirectView;

import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;

/**
 * 处理微信auth2.0授权
 */
@Slf4j
@RequestMapping("/auth/")
@RestController
public class AuthController {

    @Autowired
    private WeChatConfig weChatConfig;

    /**
     * 返回授权地址,用于微信中用户再次确认授权
     * 参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
     *
     * @param appId
     * @param redirectUrl
     * @return
     */
    @ResponseBody
    @GetMapping("/getOauthUrl")
    public String getOauthUrl(@RequestParam("app_id") String appId, @RequestParam("redirect_url") String redirectUrl) {
        String localAuthHandleUrl = this.getLocalAuthHandleUrl(appId);
        WxMpService wxMpService = weChatConfig.getWxMpService(appId);
        String oauthUrl = wxMpService.oauth2buildAuthorizationUrl(localAuthHandleUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, this.urlEncode(redirectUrl));
        log.info("【微信网页授权】获取code,oauthUrl={}", oauthUrl);
        return oauthUrl;
    }

    /**
     * 构造授权地址,并直接重定向,用于微信中用户再次确认授权
     * 参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
     *
     * @param appId
     * @param redirectUrl
     * @return
     */
    @GetMapping("/redirectOauthUrl")
    public RedirectView redirectAuthorizeUrl(@RequestParam("app_id") String appId, @RequestParam("redirect_url") String redirectUrl) {
        String localAuthHandleUrl = this.getLocalAuthHandleUrl(appId);
        WxMpService wxMpService = weChatConfig.getWxMpService(appId);
        String oauthUrl = wxMpService.oauth2buildAuthorizationUrl(localAuthHandleUrl, WxConsts.OAuth2Scope.SNSAPI_USERINFO, this.urlEncode(redirectUrl));
        log.info("【微信网页授权】获取code,oauthUrl={}", oauthUrl);
        return new RedirectView(oauthUrl);
    }

    /**
     * 处理微信授权回调
     * 参考:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
     *
     * @param code
     * @param returnUrl
     * @return
     * @throws Exception
     */
    @GetMapping("/callback/{app_id}")
    public RedirectView callback(@PathVariable("app_id") String appId,
                                  @RequestParam("code") String code,
                                  @RequestParam("state") String returnUrl) throws Exception {
        log.info("【微信网页授权】code={}", code);
        log.info("【微信网页授权】state={}", returnUrl);

        WxMpService wxMpService = weChatConfig.getWxMpService(appId);

        WxMpOAuth2AccessToken wxMpOauth2AccessToken;
        try {
            //获取access_token
            wxMpOauth2AccessToken = wxMpService.oauth2getAccessToken(code);
        } catch (WxErrorException e) {
            log.info("微信网页授权,error:{},{}", e.getMessage(), e);
            throw new Exception(e.getError().getErrorMsg());
        }

        String openId = wxMpOauth2AccessToken.getOpenId();
        log.info("【微信网页授权】openId={}", openId);

        //这里的access-token是个人的,不是全局那个access-token,不能全局共享
        //获得用户基本信息
        //WxMpUser mpUser = wxMpService.oauth2getUserInfo(wxMpOauth2AccessToken, null);
        //log.info("【微信网页授权】用户信息={}", JSONObject.toJSONString(mpUser));

        //如果有配置动态获取授权跳转地址,则使用,否则使用菜单中默认配置好的跳转地址
        String redirectUrl = this.getOauthRedirectUrl(appId, openId);
        if (StringUtils.isBlank(redirectUrl)) {
            Map<String, String> params = new HashMap<>(2);
            params.put("openid", openId);
            params.put("app_id", appId);
            redirectUrl = this.appendParam(returnUrl, params);
        }

        return new RedirectView(redirectUrl);
    }

    /**
     * 获取授权通过后重定向后的地址
     *
     * @param appId
     * @param openId
     * @return
     */
    @Nullable
    private String getOauthRedirectUrl(String appId, String openId) {
        //TODO: 实现调转地址的db化
        return "http://www.baidu.com";
    }

    /**
     * 获取本地授权地址
     *
     * @return
     */
    private String getLocalAuthHandleUrl(String appId) {
        return WeChatConfig.CURRENT_HOST + "/auth/callback/" + appId;
    }

    private String urlEncode(String str) {
        try {
            return URLEncoder.encode(str, "utf8");
        } catch (Exception var3) {
            return str;
        }
    }

    private String appendParam(String originUrl, Map<String, String> appendParams) {
        URL url = newUrl(originUrl);
        if (Objects.isNull(url)) {
            return "";
        } else {
            StringBuilder sb = new StringBuilder(url.getProtocol());
            sb.append("://");
            sb.append(url.getHost());
            if (url.getPort() > -1) {
                sb.append(":");
                sb.append(url.getPort());
            }

            sb.append(url.getPath());
            sb.append("?");
            if (StringUtils.isNoneBlank(new CharSequence[]{url.getQuery()})) {
                String[] queryArr = StringUtils.split(url.getQuery(), "&");
                Map<String, String> params = new LinkedHashMap(queryArr.length);
                String[] var6 = queryArr;
                int var7 = queryArr.length;

                for (int var8 = 0; var8 < var7; ++var8) {
                    String item = var6[var8];
                    if (StringUtils.isNoneBlank(new CharSequence[]{item})) {
                        String[] itemArr = StringUtils.split(item, "=");
                        params.put(itemArr[0], itemArr[1]);
                    }
                }

                params.putAll(appendParams);
                sb.append(this.buildQuery(params));
            } else {
                sb.append(this.buildQuery(appendParams));
            }

            if (StringUtils.isNoneBlank(new CharSequence[]{url.getRef()})) {
                sb.append("#");
                sb.append(url.getRef());
            }

            return sb.toString();
        }
    }

    private String buildQuery(Map<String, String> params) {
        StringBuilder sb = new StringBuilder();
        int total = params.size();
        Iterator var3 = params.entrySet().iterator();

        while (var3.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry) var3.next();
            --total;
            sb.append((String) entry.getKey());
            sb.append("=");
            sb.append((String) entry.getValue());
            if (total > 0) {
                sb.append("&");
            }
        }

        return sb.toString();
    }

    private URL newUrl(String url) {
        try {
            return new URL(url);
        } catch (MalformedURLException var2) {
            log.error("实例化URI失败,error:{},{}", var2.getMessage(), var2);
            return null;
        }
    }
}

 

 

 

PS:

公众号开发文档wiki

Java开发微信公众号之整合weixin-java-tools框架开发微信公众号

从零实现 Spring Boot 2.0 整合 weixin-java-mp(weixin-java-tools) 获取 openId,用于微信授权

 

Demo 列表

  1. 微信支付 Demo:GitHub码云
  2. 企业号/企业微信 Demo:GitHub码云
  3. 微信小程序 Demo:GitHub码云
  4. 开放平台 Demo:GitHub码云
  5. 公众号 Demo:
    • 使用 Spring MVC 实现的公众号 Demo:GitHub码云
    • 使用 Spring Boot 实现的公众号 Demo(支持多公众号):GitHub码云
    • 含公众号和部分微信支付代码的 Demo:GitHub码云

 

posted @ 2020-03-24 11:53  phpdragon  阅读(815)  评论(0编辑  收藏  举报