“This is my fourth day of participating in the First Challenge 2022. For more details: First Challenge 2022.”

The introduction

Hello, this is Anyin.

Today we’re going to talk about some of the things we’ve encountered with wechat login and registration.

In our business system, a user must have a unique identity in the system, and this unique identity is generally obtained from the outside of the system, rather than automatically generated by the system, such as mobile phone number or ID card.

In the case of wechat (wechat public account H5 or Small program), the unique identification of users is generally mobile phone number or OpenID. Under normal circumstances, what we encounter is that a user has only one wechat signal, and a wechat signal is bound to a mobile phone number, so we think the relationship between the three is as follows:

However, the ideal is full, the reality is very skinny, the situation we encounter will certainly not be so simple.

Problem analysis

When a system runs long enough and has enough users, you get all sorts of weird problems.

In the previous section, we know that the normal scenario is relatively simple. The relationship among the user, wechat signal and mobile phone number is 1:1:1, which means that the three can be equivalent. If I use one of the information, I can always query the information of the other two.

Therefore, according to the above ideas, it is easy to design the user table: CUS_info, the basic table structure is as follows:

The user ID WeChat openid User’s Mobile phone Number Logic to delete The other fields
id openid mobile del_flg .

However, this table structure design does not meet the requirements in the following two scenarios.

Some users have two wechat signals and are bound to the same mobile phone number (this logic can be achieved by changing the mobile phone number through wechat).

In this scenario, once the user logs in to the system with a different wechat account, the user logs in according to the wechat OpenID. Since the openID cannot be found in the table data, the registration process is followed. When registering, the user information is queried according to the mobile phone number. The user already exists, and the login process is returned, resulting in an endless logical loop.

One user has two mobile phone numbers. In addition, some users have two mobile phone numbers and are bound to the same mobile phone number (this logic is realized by adding another mobile phone number when the user authorizes the mobile phone number).

In this scenario, the first user registers and logs in using mobile phone number A, and we bind mobile phone number A and corresponding wechat OpenID at the back end. The second time the user registers and logs in with the mobile phone number B, at this time the database will have two records, which are the same OpenID for different mobile phone numbers. This can cause two users to be found when retrieving user information from OpenID in some scenarios (such as payment callback), resulting in a business exception.

solution

Different people have different solutions to the above two problems in different business scenarios. Some use mobile phone number as the unique identifier of the user, while others use wechat OpenID as the unique identifier of the user. Here, we provide the solution of using the mobile phone number as the unique identification of the user.

Here, we believe that a mobile phone number is a user, and a user will have multiple wechat signals. The relationship is as follows:

To solve this problem, we will ensure that only one wechat OpenID can be found for a mobile phone number through logical control during login and registration. The processing method is as follows:

  • Query all wechat Openids according to the current mobile phone number and delete them logically
  • All mobile phone numbers are queried according to the current OpenID and are logically deleted
  • Check whether there are records based on the current mobile phone number and OpenID. If there are no records, the records will be added. If there are records, the logical deletion flag will be reset to normal.

One user has two mobile phone numbers. For this problem, we deal with it in business. Because we think that a mobile phone number is one user, if a user has two mobile phone numbers, then in our system we consider two users, their data is independent of each other.

In addition, in this scenario, we also need to provide a mobile phone number for binding function. In this way, when the user has two mobile phone numbers, it can also realize the need to switch.

Plan implementation

Above, we have the relevant solutions. Then it’s design and coding.

Based on the above, we will design the following 2 table structures:

Cus_info User information table

The user ID User’s Mobile phone Number Logic to delete The other fields
id mobile del_flg .

Cus_wx_info Association table between users and wechat

ID User’s Mobile phone Number WeChat appId WeChat openid Open platform UnionID Logic to delete The other fields
id mobile app_id openid unionid del_flg .

Here we add a field of app_ID and a field of unionID, which is used when our business involves multiple entrances, such as wechat public number H5 entrance and wechat mini program.

Different users may have the same or different OpenIDS generated by wechat public account H5 and wechat mini program, so we need to distinguish them by app_id

At the same time, in order to associate the users of wechat public account H5 and wechat small program, we will bind the wechat public account and wechat small program to the same open platform. At this time, a unionID will be generated, through which users of wechat public account can be found, and users of wechat small program can be found.

Next we implement a registration method.

@Service
public class CsInfoServiceImpl implements CsInfoService {
    @Autowired
    private CsInfoRepository csInfoRepository;

    @Autowired
    private CsWxInfoRepository csWxInfoRepository;

    @Autowired
    private CsInfoConvert csInfoConvert;
    
    @Override
    @Transactional(rollbackFor = Throwable.class, timeout = 60)
    public CsWxInfoDTO register(CsInfoRegisterDTO param) {
        // Query user information based on mobile phone number
        CsInfo info = csInfoRepository.infoByMobile(param.getMobile());
        Long id = info == null ? 0 : info.getId();
        // If the user does not exist, create one
        if(id == 0){
            id = csInfoRepository.create(param.getMobile(), param.getRegisterSource().getCode());
        }
        // Logically delete the openID bound to the current mobile number
        // Logically delete the mobile phone number bound to the current OpenID
        csWxInfoRepository.handleOpenidMobileUnique(param.getMobile(), param.getOpenid(), param.getAppId());
        
        // Ensure the 1:1 relationship between the current mobile number and openID in the system
        CsWxInfo wxInfo = csWxInfoRepository.infoByMobileOpenid(param.getMobile(), param.getOpenid(), param.getAppId());
        if(wxInfo == null){
            wxInfo = new CsWxInfo();
            wxInfo.setAppId(param.getAppId());
            wxInfo.setMobile(param.getMobile());
            wxInfo.setOpenid(param.getOpenid());
            wxInfo.setUnionid(param.getUnionid());
            wxInfo.setAvatarUrl(param.getAvatarUrl());
            wxInfo.setNickName(param.getNickName());
            csWxInfoRepository.save(wxInfo);
        }else{
            CsWxInfo model = new CsWxInfo();
            model.setId(wxInfo.getId());
            model.setDelFlg(Integer.valueOf(DelFlgEnum.NORMAL.getCode()));
            csWxInfoRepository.updateById(model);
        }

        CsWxInfoDTO result = csInfoConvert.getCsWxInfoDTO(wxInfo);
        result.setInfoId(id);
        returnresult; }}Copy the code

The SQL processing corresponding to handleOpenidMobileUnique is as follows:

    <update id="loginDelByOpenIdExcludeMobile">
        update cs_wx_info set del_flg = 0 ,update_time = now()
        <where>
            del_flg = 1
            <if test="appId ! = null">
                and app_id = #{appId}
            </if>
            <if test="openid ! = null and openid ! = "">
                and openid = #{openid}
            </if>
            <if test="mobile ! = null and mobile ! = "">and mobile ! = #{mobile}</if>
        </where>
    </update>

    <update id="loginDelByMobileExcludeOpenid">
        update cs_wx_info set del_flg = 0 ,update_time = now()
        <where>
            del_flg = 1
            <if test="appId ! = null">
                and app_id = #{appId}
            </if>
            <if test="mobile ! = null and mobile ! = "">
                and mobile = #{mobile}
            </if>
            <if test="openid ! = null and openid ! = "">and openid ! = #{openid}</if>
        </where>
    </update>
Copy the code

The last

So far, about the micro channel login registration encountered some small problems, we found a relatively good solution, you are not quick to practice your own project?

Anyin Cloud