Third party login - wechat login

Keywords: Java wechat

Recently, due to the needs of the project, it is necessary to realize the function of wechat code scanning in the project. Wechat code scanning login is a very common technology now. Code scanning is used in many places, which is not only convenient and fast, but also relatively safe. After referring to some big guys' articles, I share my understanding with you. You are welcome to correct the shortcomings. Thank you.

preparation

1. Using wechat login is to register a developer account on the wechat open platform and have it verified by the bank. After passing the verification, you need to create a website application and a domain name as a callback for wechat. After creating the website application, you will get an appid and appsecret, configure the callback domain, and end some pre requirements.

Wechat development platform link    https://open.weixin.qq.com/

2. Understand the wechat login process and related technologies

These are introduced in the development documents. Here I will tell you about my own understanding of the wechat login process

First, the official gives the basic flow chart, but the details are not detailed. The following figure is the official flow chart

1. Get code

First, the user needs to initiate a wechat code scanning login request in the third-party application, and then the third-party application sends a request to the wechat open platform through OAuth2.0 to pull up the code scanning login request. The wechat development platform will return a code scanning interface to the third-party application through the callback field of the network application, and the user will scan the code to confirm login, The wechat development platform will pull up or redirect to a third party and carry a temporary bill (code)

2. Get the token (access) through code_ token)

After the third-party application obtains the code returned by the wechat development platform, it obtains the token from the wechat open platform according to the connection provided by it

  After obtaining the code of the first step, request the following link to obtain access_token:

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

Because appid and other parameters are very verbose, set them as constants to avoid errors

/**
 * Get token constant class
 * @author
 */
public class WxConstants {
    public static final String APPID = "Own website application APPID ";
    public static final String SECRET = "Own website application SECRET ";
    /**
     *  Get token token through code appid secret
     */
    public static final String GET_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    /**
     * Get user information
     */
    public static final String GET_USER_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";

}

        Return Description:

{
  "access_token": "ACCESS_TOKEN",
  "expires_in": 7200,
  "refresh_token": "REFRESH_TOKEN",
  "openid": "OPENID",
  "scope": "SCOPE",
  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
} 

parameter                    explain
access_token       Interface call voucher
expires_in         access_token Timeout time of interface call voucher, unit (s)
refresh_token      User refresh access_token
openid             Unique ID of authorized user
scope              Scope of user authorization, using commas(,)separate

Refresh access_ Valid period of token

access_token is the calling voucher for calling the authorization relationship interface_ The validity period of the token (currently 2 hours) is short, when access_ After the token times out, you can use refresh_ Refresh with token, access_ There are two types of token refresh results:

1. if access_token Timeout, proceed refresh_token Will get a new access_token,New timeout;
2. if access_token If not, proceed refresh_token Will not change access_token,But the timeout will refresh, which is equivalent to renewal access_token. 

refresh_token has a long validity period (30 days), when refresh_ After the token becomes invalid, the user needs to re authorize.

Request method

After obtaining the code of the first step, request the following link to refresh_token:

https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN

Parameter description
 parameter	             Is it necessary	            explain
appid	           yes	            Apply unique identification
grant_type	       yes	            fill refresh_token
refresh_token	   yes	            Fill in through access_token Obtained refresh_token parameter

 

3. Realize wechat code scanning login

Get access_ After token, we can get the relevant information of the logged in user and operate. Getting the user data is the beginning of this function. How to realize the user code scanning login requires us to complete the data operation ourselves.

In this project, a table is used to store all the data of user code scanning login, and some tables are associated with it, such as user information table, user login table and other tables that need this data.

After the user scans the code and obtains the user data, the bank judges whether it is the first login or an existing account. If it is an existing account, it only needs to associate the relevant information of wechat login with its corresponding user information. If it is the first login, it needs to register an account in the system to store the user's information.

/**
     * Wechat login
     * @param map
     * @return
     */
    @Override
    public Ajaxresult wechat(Map<String, String> map) {
        String code=map.get("code");
        System.out.println(code);
        if (StringUtils.isEmpty(code)){
                throw  new MyExpection("System error");
        }
        //Get token token through code appid secret
        String url= WxConstants.GET_TOKEN_URL.replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE",code);
        //Send request and get token
        String obj = HttpClientUtils.httpGet(url);
        System.out.println(obj);
        // Convert json string to json object
        JSONObject jsonObject = JSONObject.parseObject(obj);
        //Get token and openid
        String token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        System.out.println(openid+"==========================================");
        //Query the object through openid and userid. If the object is not empty, it indicates that it has been logged in. If the object is empty, it indicates that it has not been logged in
        WxUser wxUser = wxUserMapper.findByOpenId(openid);

        // Get user information at the first scan
        String param = "?token="+token+"&openid="+openid;

        //Judge whether the object exists and userId exists
        if (wxUser !=null && wxUser.getUser_id()!=null){
            //Get user information
           LoginInfo loginInfo=loginInfoMapper.findByUserId(wxUser.getUser_id());
            // 4,1 get token
            String userToken = UUID.randomUUID().toString();
            //  Store the user information in redis, and the expiration time is 30 minutes
            redisTemplate.opsForValue().set(userToken,
                    loginInfo,
                    30,
                    TimeUnit.MINUTES);
          Map<String,Object> wxMap=new HashMap<>();
            wxMap.put("token", userToken);

            // Set the user name and password to null
            loginInfo.setPassword("");
            loginInfo.setSalt("");
            // Object to be serialized
            wxMap.put("loginInfo",loginInfo);
            return Ajaxresult.me().setResultObj(wxMap);
        }

       return Ajaxresult.me().setSuccess().setResultObj(param);
    }

    /**
     * Wechat registration binding
     * @param map
     * @return
     */
    @Override
    public Map<String, Object> binder(Map<String, String> map) {
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        //1. Null verification
        if(StringUtils.isEmpty(phone)){
            throw new MyExpection("The phone number cannot be blank. Please enter the phone number");
        }
        //2. Verification code verification
        //Get verification code
        Object obj = redisTemplate.opsForValue().get("binder:"+phone);
        String time = obj.toString().split(":")[1];
        //1. Is the verification code expired
        if(System.currentTimeMillis() - Long.valueOf(time)>180*1000){
            throw new MyExpection("The verification code has expired. Please obtain the verification code again");
        }else {
            // 2. Judge whether the verification codes are consistent
            //Get verification code
            String code = obj.toString().split(":")[0];
            if (! verifyCode.equals(code)){
                throw new MyExpection("Verification code error, please re-enter");
            }
        }
        //3. Judge whether the mobile phone number has been registered
        User user = userMapper.findByPhone(phone);
        LoginInfo loginInfo=null;
        User userTemp=null;
        //Registered
        if (user!=null){
            loginInfo=loginInfoMapper.findByUserId(userTemp.getId());
            System.out.println(loginInfo);
            userTemp=user;
        }else {
            //Not registered, save three tables loginInfo user wxUser
            userTemp=initUser(phone);
            loginInfo=initLoginInfo(userTemp);
            //Store the data in the corresponding table
            loginInfo.setType(1);
            loginInfoMapper.add(loginInfo);
            //Store information in the user table
            userTemp.setLogininfo(loginInfo);
            userMapper.add(userTemp);

        }
        //Save information to wxUser
        String replace = HttpClientUtils.httpGet(WxConstants.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId));
        // System.out.println(obj+"=======================================");

        //Add information to wxUser
        WxUser wxUser=initWxuser(replace);
        //binding
        wxUser.setUser_id(userTemp.getId());
        //Save to table
        wxUserMapper.add(wxUser);

        //Save data to redis
        String userToken = UUID.randomUUID().toString();
        //  Store the user information in redis, and the expiration time is 30 minutes
        redisTemplate.opsForValue().set(userToken,
                loginInfo,
                30,
                TimeUnit.MINUTES);
        Map<String,Object> binderMap=new HashMap<>();
        binderMap.put("token", userToken);
        // Set the user name and password to null
        loginInfo.setPassword("");
        loginInfo.setSalt("");
        // Object to be serialized
        binderMap.put("loginInfo",loginInfo);
        return binderMap;
    }

Posted by mjlogan on Wed, 01 Sep 2021 22:18:06 -0700