All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.bootystar.wechat.officialAccount.module.web.WebApi Maven / Gradle / Ivy

The newest version!
package io.github.bootystar.wechat.officialAccount.module.web;

import com.alibaba.fastjson2.JSON;
import io.github.bootystar.tool.HttpTool;
import io.github.bootystar.tool.ObjectTool;
import io.github.bootystar.wechat.core.ResponseBase;
import io.github.bootystar.wechat.core.exception.ResponseException;
import lombok.SneakyThrows;

import java.net.URLEncoder;
import java.time.LocalDateTime;

/**
 * 微信网页开发API
 * @author booty
 * 
 */
public class WebApi {

    /**
     *     以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
     *     以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息
     *     应用授权作用域,
     *     snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),
     *     snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
     *     用户同意授权后
     *     如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE
     */
    private final static String URL_OAUTH2_URL="https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
    public static final String SCOPE_SNSAPI_BASE = "snsapi_base";
    public static final String SCOPE_SNSAPI_USERINFO = "snsapi_userinfo";


    /**
     * 获取snsapi_base作用域的授权url
     *
     * @param appId       应用程序id
     * @param redirectURL 重定向url
     * @return {@code String }
     * @author booty
     * 
     */
    @SneakyThrows
    public static String oAuth2UrlBase(String appId ,String redirectURL){
        String url = URL_OAUTH2_URL.replace("APPID", appId);
        url = url.replace("REDIRECT_URI", URLEncoder.encode(redirectURL, "UTF-8"));
        url = url.replace("SCOPE", SCOPE_SNSAPI_BASE);
        url = url.replace("STATE", "");
        return url;
    }


    /**
     * 获取snsapi_userinfo作用域的授权url
     *
     * @param appId       应用程序id
     * @param redirectURL 重定向url
     * @return {@code String }
     * @author booty
     * 
     */
    @SneakyThrows
    public static String oAuth2UrlUserInfo(String appId,String redirectURL){
        String url = URL_OAUTH2_URL.replace("APPID", appId);
        url = url.replace("REDIRECT_URI", URLEncoder.encode(redirectURL, "UTF-8"));
        url = url.replace("SCOPE", SCOPE_SNSAPI_USERINFO);
        url = url.replace("STATE", "");
        return url;
    }

    /**
     * 获取指定作用域的授权url
     *
     * @param appId       appId
     * @param redirectURL 重定向url
     * @param scope       范围
     * @param state       状态  重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
     * @return {@code String }
     * @author booty
     * 
     */
    @SneakyThrows
    public static String oAuth2Url(String appId ,String redirectURL,String scope,String state){
        String url = URL_OAUTH2_URL.replace("APPID", appId);
        url = url.replace("REDIRECT_URI", URLEncoder.encode(redirectURL, "UTF-8"));
        url = url.replace("SCOPE", scope);
        url = url.replace("STATE", state);
        return url;
    }


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

    /**
     * 创建用户访问令牌
     *
     * 这里通过code换取的是一个特殊的网页授权access_token,
     * 与基础支持中的access_token(该access_token用于调用其他接口)不同。
     * 公众号可通过下述接口来获取网页授权access_token。
     * 如果网页授权的作用域为snsapi_base,则本步骤中获取到网页授权access_token的同时,也获取到了openid,snsapi_base式的网页授权流程即到此为止。
     *
     * 尤其注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。
     * 后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。
     *
     * @param appId     应用程序id
     * @param appSecret 应用程序秘密
     * @param code      代码
     * @return {@code UserAccessToken }
     * @author booty
     * 
     */
    public static UserAccessToken createUserAccessToken(String appId, String appSecret, String code){
        String url = GET_PERSONAL_TOKEN_URL.replace("APPID", appId).replace("SECRET", appSecret).replace("CODE",code);
        String result = HttpTool.doGet(url);
        /*
            {
              "access_token":"ACCESS_TOKEN",
              "expires_in":7200,
              "refresh_token":"REFRESH_TOKEN",
              "openid":"OPENID",
              "scope":"SCOPE",
              "is_snapshotuser": 1,
              "unionid": "UNIONID"
            }
         */
        UserAccessToken token = JSON.parseObject(result, UserAccessToken.class);
        if (ObjectTool.isEmpty(token.getAccess_token())){
            throw new ResponseException(token);
        }
        // 设置过期时间
        token.setExpiresTime(LocalDateTime.now().plusSeconds(token.getExpires_in()));
        return token;
    }

    private static final String GET_CHECK_PERSONAL_TOKEN_URL ="https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID";


    /**
     * 检验授权凭证(access_token)是否有效
     * ResponseBase.errcode=0 时表示有效
     *
     * @param token  令牌
     * @param openId 开放id
     * @return {@code ResponseBase }
     * @author booty
     * 
     */
    public static ResponseBase checkUserAccessToken(String token,String openId){
        String url = GET_CHECK_PERSONAL_TOKEN_URL.replace("ACCESS_TOKEN", token).replace("OPENID",openId);
        String result = HttpTool.doGet(url);
        /*
        { "errcode":0,"errmsg":"ok"}
         */
        return JSON.parseObject(result, ResponseBase.class);
    }




    private static final String REFRESH_PERSONAL_TOKEN_URL="https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN";

    /**
     * 刷新用户访问令牌
     * 由于access_token拥有较短的有效期,当access_token超时后,可以使用refresh_token进行刷新,
     * refresh_token有效期为30天,当refresh_token失效之后,需要用户重新授权
     *
     * @param appId    应用程序id
     * @param oldToken 旧令牌
     * @return {@code UserAccessToken }
     * @author booty
     * 
     */
    public static UserAccessToken refreshUserAccessToken(String appId,String oldToken){
        String url = GET_PERSONAL_TOKEN_URL.replace("APPID", appId).replace("REFRESH_TOKEN", oldToken);
        String result = HttpTool.doGet(url);
        /*
        {
          "access_token":"ACCESS_TOKEN",
          "expires_in":7200,
          "refresh_token":"REFRESH_TOKEN",
          "openid":"OPENID",
          "scope":"SCOPE"
        }
         */
        UserAccessToken token = JSON.parseObject(result, UserAccessToken.class);
        // 设置过期时间
        token.setExpiresTime(LocalDateTime.now().plusSeconds(token.getExpires_in()));
        if (ObjectTool.isEmpty(token.getAccess_token())){
//            String msg=String.format("wechat userToken required failed,response code:%s, responseMsg:%s",token.getErrcode(),token.getErrmsg());
            throw new ResponseException(token);
        }
        return token;
    }


    private final static String GET_USER_INFO_URL="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";

    /**
     * 根据openId获取用户信息
     *
     * @param token  用户个人令牌
     * @param openId 开放id
     * @return {@code UserInfo }
     * @author booty
     * 
     */
    public static UserInfo getUserInfoByOpenId(String token,String openId){
        String url = GET_USER_INFO_URL.replace("ACCESS_TOKEN", token).replace("OPENID", openId);
         /*
        若出现乱码问题,不再使用HttpTool,启用此行代码
            try {
                url1 = new URL(url);
                urlConnection = (HttpURLConnection)url1.openConnection();
                try (InputStream inputStream = urlConnection.getInputStream();
                     InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
                     BufferedReader in = new BufferedReader(inputStreamReader);
                ){
                    String result = in.readLine();
                    urlConnection.disconnect();
                    UserInfo userInfo = JSON.parseObject(result, UserInfo.class);
                    UserInfo userInfo = JSON.parseObject(result, UserInfo.class);
                    if (ObjectTool.isEmpty(userInfo.getOpenid())){
                        throw new WechatResponseException(userInfo);
                    }
                    return userInfo;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
         */
        String result = HttpTool.doGet(url);
        /*
        {
          "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"
        }
         */
        UserInfo userInfo = JSON.parseObject(result, UserInfo.class);
        if (ObjectTool.isEmpty(userInfo.getOpenid())){
            throw new ResponseException(userInfo);
        }
        return userInfo;
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy