background

With the widespread use of wechat, the development of web pages for wechat service numbers is also a common demand. One of the most common links is the oAuth login of wechat to obtain the wechat information of users, so as to save users from the trouble of repeated registration in wechat scenarios.

WeChat official request login details are given: developers.weixin.qq.com/doc/offiacc…

In actual development, it usually follows the same process to jump to the page from the web page, initiate oAuth request to wechat server, get code and then jump back to obtain access_token and user information.

However, for security reasons, wechat requires to add a trusted domain name. Only the jump initiated on the trusted domain name can obtain oAuth information. This creates problems for wechat login in the development environment.

If we want to unify in the local development environment, also can wechat login, how to do?

methods

The idea is to pull out the wechat related login services, fixed deployment in a domain name server. Let us no matter where the login request comes from, can be unified from an online fixed domain name server to the wechat server. You can also log in to wechat in the local.

The steps are as follows:

  1. The front end initiates a login request to obtain user information
  2. After receiving the request, the server jumps to the wechat oAuth login page with the current page and the auth_callBack address after processing the user information in state. CallBack is set as bolt server specialized in processing wechat actions to get the API interface after code.
  3. After completing the authorized login, the user jumps to bolt server and obtains user information by using code.
  4. The Bolt server uses the auth_callBack address in state to jump to the corresponding interface of the application server, and carries the user information and user access page in the query parameters.
  5. On the corresponding interface, the application server sets the token in the cookie according to the obtained user information and redirects to the original page. The front-end can log in with the token.

code

The key codes are as follows:

Application server

const wechatLoginRedirect = R.curry(
  async (isOpen: boolean, ctx: IRouterContext) => {
    const protocal = ctx.protocol;
    const host = ctx.host;
    const { state = '/' } = ctx.query;
    const callbackUrl = `${protocal}: / /${host}/passport/wechat_login_callback`;
    const { AppID, LoginUrl, RedirectUrl } = isOpen
      ? WechatOpen
      : WechatAccount;
    const scope = isOpen ? 'snsapi_login' : 'snsapi_userinfo';
    const redirectUrl = `${RedirectUrl}? callbackUrl=The ${encodeURIComponent(
      callbackUrl
    )}`;
    consturl = getLoginUrl(AppID, LoginUrl, redirectUrl, scope, state); ctx.redirect(url); });const wechatAccountLoginRedirect = wechatLoginRedirect(false);
const wechatOpenLoginRedirect = wechatLoginRedirect(true);

Passport.get('/wechat_login_open', wechatOpenLoginRedirect);
Passport.get('/wechat_login', wechatAccountLoginRedirect);

Copy the code
const wechatLoginCallback = async (ctx: IRouterContext) => {
  const { userInfo, state = '/' } = ctx.query;
  const jsonUserInfo = JSON.parse(userInfo);
  const userProfile = await getUserProfileByWechat(jsonUserInfo);
  const userId = userProfile.id;
  const userIdToken = jwt.sign(userId, TOKEN_KEY);
  ctx.cookies.set('token', userIdToken, {
    httpOnly: true.maxAge: 30 * 24 * 60 * 60 * 1000.signed: true}); ctx.redirect(state); }; Passport.get('/wechat_login_callback', wechatLoginCallback);
Copy the code

Bolt server

router.get('/auth'.async (ctx) => {
  const { code, callbackUrl, state } = ctx.query;

  const { AppID, AppSecret } = WechatAccount;
  const redirectUrl = await getRedirectUrlWithWechatUser(
    ctx,
    callbackUrl,
    AppID,
    AppSecret,
    code,
    state
  );
  ctx.redirect(redirectUrl);
  return ctx.response;
});

router.get('/auth/open'.async (ctx) => {
  const { code, callbackUrl, state } = ctx.query;
  const { AppID, AppSecret } = WechatOpen;
  const redirectUrl = await getRedirectUrlWithWechatUser(
    ctx,
    callbackUrl,
    AppID,
    AppSecret,
    code,
    state
  );
  ctx.redirect(redirectUrl);
  return ctx.response;
});
Copy the code
const getRedirectUrlWithWechatUser = async (
  ctx,
  callbackUrl = CallBackUrl,
  appId,
  appSecret,
  code,
  state
) => {
  const {
    data: { access_token, openid },
  } = await getWechatAccessToken(ctx, appId, appSecret, code);

  const { data: objUserInfo } = await getWechatUserInfo(
    ctx,
    access_token,
    openid
  );

  const userInfo = JSON.stringify(objUserInfo);
  const strQuery = qs.stringify({ userInfo, state });
  const containQueryAlready = callbackUrl.indexOf('? ')! = = -1;
  const redirectUtl = `${callbackUrl}${
    containQueryAlready ? '&' : '? '
  }${strQuery}`;
  return redirectUtl;
};
Copy the code

conclusion

In the face of third-party access, which is difficult to debug online, you can carefully consider the specific process and separate the core parts. And transactions are handled in the process via HTTP jumps.

This article is participating in the “Nuggets 2021 Spring Recruitment Campaign”, click to see the details of the campaign