1. 程式人生 > 其它 >微信回撥URL實戰

微信回撥URL實戰

技術標籤:javajava

一準備

1httpclient工具類

package com.atguigu.guli.common.base.util;


import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;


import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;


/**
* @className: HttpClientUtils
* @description: http請求客戶端
* @date: 2021/1/2
* @author: cakin
*/
public class HttpClientUtils {
   private String url;
   private Map<String, String> param;
   private int statusCode;
   private String content;
   private String xmlParam;
   private boolean isHttps;


   public boolean isHttps() {
      return isHttps;
   }


   public void setHttps(boolean isHttps) {
      this.isHttps = isHttps;
   }


   public String getXmlParam() {
      return xmlParam;
   }


   public void setXmlParam(String xmlParam) {
      this.xmlParam = xmlParam;
   }


   public HttpClientUtils(String url, Map<String, String> param) {
      this.url = url;
      this.param = param;
   }


   public HttpClientUtils(String url) {
      this.url = url;
   }


   public void setParameter(Map<String, String> map) {
      param = map;
   }


   public void addParameter(String key, String value) {
      if (param == null)
         param = new HashMap<String, String>();
      param.put(key, value);
   }


   public void post() throws ClientProtocolException, IOException {
      HttpPost http = new HttpPost(url);
      setEntity(http);
      execute(http);
   }


   public void put() throws ClientProtocolException, IOException {
      HttpPut http = new HttpPut(url);
      setEntity(http);
      execute(http);
   }


   public void get() throws ClientProtocolException, IOException {
      if (param != null) {
         StringBuilder url = new StringBuilder(this.url);
         boolean isFirst = true;
         for (String key : param.keySet()) {
            if (isFirst) {
               url.append("?");
               isFirst = false;
            }else {
               url.append("&");
            }
            url.append(key).append("=").append(param.get(key));
         }
         this.url = url.toString();
      }
      HttpGet http = new HttpGet(url);
      execute(http);
   }


   /**
    * set http post,put param
    */
   private void setEntity(HttpEntityEnclosingRequestBase http) {
      if (param != null) {
         List<NameValuePair> nvps = new LinkedList<NameValuePair>();
         for (String key : param.keySet())
            nvps.add(new BasicNameValuePair(key, param.get(key))); // 引數
         http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 設定引數
      }
      if (xmlParam != null) {
         http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
      }
   }


   private void execute(HttpUriRequest http) throws ClientProtocolException,
         IOException {
      CloseableHttpClient httpClient = null;
      try {
         if (isHttps) {
            SSLContext sslContext = new SSLContextBuilder()
                  .loadTrustMaterial(null, new TrustStrategy() {
                     // 信任所有
                     public boolean isTrusted(X509Certificate[] chain,
                           String authType)
                           throws CertificateException {
                        return true;
                     }
                  }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                  sslContext);
            httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
                  .build();
         } else {
            httpClient = HttpClients.createDefault();
         }
         CloseableHttpResponse response = httpClient.execute(http);
         try {
            if (response != null) {
               if (response.getStatusLine() != null)
                  statusCode = response.getStatusLine().getStatusCode();
               HttpEntity entity = response.getEntity();
               // 響應內容
               content = EntityUtils.toString(entity, Consts.UTF_8);
            }
         } finally {
            response.close();
         }
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         httpClient.close();
      }
   }


   public int getStatusCode() {
      return statusCode;
   }


   public String getContent() throws ParseException, IOException {
      return content;
   }


}

2pom依賴

<!--httpclient-->
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

二獲取access_token

/**
* 功能描述:阿里雲對本地的回撥
*
* @param code    認證code
* @param state   認證狀態
* @param session session
* @return
* @author cakin
* @date 2021/1/2
* @description:
*/
@GetMapping("callback")
public String callback(String code, String state, HttpSession session) {
    System.out.println("callback被呼叫");
    System.out.println("code:" + code);
    System.out.println("state:" + state);
    if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {
        log.error("非法回撥請求");
        throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
    }
    String sessionState = (String) session.getAttribute("wx_open_state");
    if (!state.equals(sessionState)) {
        log.error("非法回撥請求");
        throw new GuliException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
    }


    // 攜帶code臨時票據,和appid以及appsecret請求access_token和openid(微信唯一標識)
    String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
    //組裝引數:?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    Map<String, String> accessTokenParam = new HashMap<>();
    accessTokenParam.put("appid", ucenterProperties.getAppId());
    accessTokenParam.put("secret", ucenterProperties.getAppSecret());
    accessTokenParam.put("code", code);
    accessTokenParam.put("grant_type", "authorization_code");
    HttpClientUtils client = new HttpClientUtils(accessTokenUrl, accessTokenParam);
    String result;
    try {
        // 傳送請求:組裝完整的url字串、傳送請求
        client.get();
        // 得到響應
        result = client.getContent();
        System.out.println("result = " + result);
    } catch (Exception e) {
        log.error("獲取access_token失敗");
        throw new GuliException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
    }
    Gson gson = new Gson();
    HashMap<String, Object> resultMap = gson.fromJson(result, HashMap.class);
    // 失敗的響應結果
    Object errcodeObj = resultMap.get("errcode");
    if (errcodeObj != null) {
        Double errcode = (Double) errcodeObj;
        String errmsg = (String) resultMap.get("errmsg");
        log.error("獲取access_token失敗:" + "code:" + errcode + ", message:" + errmsg);
        throw new GuliException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
    }
    // 成功響應:解析出結果中的access_token和openid
    String accessToken = (String) resultMap.get("access_token");
    String openid = (String) resultMap.get("openid");
    System.out.println("accessToken:" + accessToken);
    System.out.println("openid:" + openid);
    return null;
}

三獲取使用者資訊

1根據openid查詢使用者是否已註冊

介面

/**
* 功能描述:根據openid查詢使用者是否已註冊
*
* @author cakin
* @date 2021/1/2
* @param openid openid
* @return Member 使用者資訊
*/
Member getByOpenid(String openid);

實現

/**
* 功能描述:根據openid查詢使用者是否已註冊
*
* @param openid openid
* @return Member 使用者資訊
* @author cakin
* @date 2021/1/2
*/
@Override
public Member getByOpenid(String openid) {
    QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("openid", openid);
    return baseMapper.selectOne(queryWrapper);
}

2根據access_token獲取使用者資訊

/**
* 功能描述:阿里雲對本地的回撥
*
* @param code    認證code
* @param state   認證狀態
* @param session session
* @return
* @author cakin
* @date 2021/1/2
* @description:
*/
@GetMapping("callback")
public String callback(String code, String state, HttpSession session) {
   ......
    // 在本地資料庫中查詢當前微信使用者的資訊
    Member member = memberService.getByOpenid(openid);
    // 沒有註冊情況
    if (member == null) {
        // 如果當前使用者不存在,則去微信的資源伺服器獲取使用者個人資訊(攜帶access_token)
        String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo";
        // 組裝引數:?access_token=ACCESS_TOKEN&openid=OPENID
        Map<String, String> baseUserInfoParam = new HashMap<>();
        baseUserInfoParam.put("access_token", accessToken);
        baseUserInfoParam.put("openid", openid);
        client = new HttpClientUtils(baseUserInfoUrl, baseUserInfoParam);
        String resultUserInfo = "";
        try {
            client.get();
            resultUserInfo = client.getContent();
        } catch (Exception e) {
            log.error(ExceptionUtils.getMessage(e));
            throw new GuliException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        HashMap<String, Object> resultUserInfoMap = gson.fromJson(resultUserInfo, HashMap.class);
        // 失敗的響應結果
        errcodeObj = resultUserInfoMap.get("errcode");
        if (errcodeObj != null) {
            Double errcode = (Double) errcodeObj;
            String errmsg = (String) resultMap.get("errmsg");
            log.error("獲取使用者資訊失敗:" + "code:" + errcode + ", message:" + errmsg);
            throw new GuliException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        // 解析出結果中的使用者個人資訊
        String nickname = (String) resultUserInfoMap.get("nickname");
        String avatar = (String) resultUserInfoMap.get("headimgurl");
        Double sex = (Double) resultUserInfoMap.get("sex");
        // 在本地資料庫中插入當前微信使用者的資訊(使用微信賬號在本地伺服器註冊新使用者)
        member = new Member();
        member.setOpenid(openid);
        member.setNickname(nickname);
        member.setAvatar(avatar);
        member.setSex(sex.intValue());
        memberService.save(member);
    }
    // 則直接使用當前使用者的資訊登入(生成jwt)
    // member =>Jwt
    JwtInfo jwtInfo = new JwtInfo();
    jwtInfo.setId(member.getId());
    jwtInfo.setNickname(member.getNickname());
    jwtInfo.setAvatar(member.getAvatar());
    String jwtToken = JwtUtils.getJwtToken(jwtInfo, 1800);
    return "redirect:http://localhost:3000?token=" + jwtToken;
}

四前端整合

  // 頁面渲染之後執行:可以有window物件
  mounted() {
    const token = this.$route.query.token
    if (token) {
      // 將jwt寫入cookie
      cookie.set('guli_jwt_token', token, { domain: 'localhost' })
      window.location.href = '/'
    }
  },