多平台多渠道账号体系绑定第一篇,微信小程序篇

由于不能上传视频,跳转观看实现效果

近来,在对接三方平台时,欲将多方开放平台统一整合入笔者的框架内。

如下为大致思路设计图

由于需对接多方平台关联账号体系,思来之后,将设计一张“三方平台中间表”。

表结构如下:

在此,将主要字段赘述一下:

platform_code:三方平台的编码,例(微信小程序、QQ小程序、微信App、百度小程序等一些三方平台),当然,笔者也会预留对应的接口,供自定义三方平台对接,实现着可在自由的业务代码中实现。

app_channel_code:应用渠道编码,为满足同一个渠道中发行了多个应用版本,故而作此区分。

表结构设计完毕,自然要与账号表进行关联,关联图如下:

既,表已设计完毕,此下将具体实现功能。

由于需要对接三方平台,笔者先定义一些小程序渠道的字典,后期再扩展其他三方渠道。

/**
 * 三方平台类型
 */
@DictionaryConfig(dictionaryCode = PlatformType.DICTIONARY_CODE, dictionaryName = "三方平台类型", remark = "三方平台类型", version = 4)
public static class PlatformType {

    public static final String DICTIONARY_CODE = "2101";
    /*==================小程序渠道================*/
    /**
     * QQ小程序
     */
    @DictionaryConfig(dictionaryName = "QQ小程序", remark = "QQ小程序")
    public static final String MP_QQ = "210101";
    /**
     * 微信小程序渠道
     */
    @DictionaryConfig(dictionaryName = "微信小程序", remark = "微信小程序")
    public static final String MP_WEIXIN = "210102";
    /**
     * 支付宝小程序
     */
    @DictionaryConfig(dictionaryName = "支付宝小程序", remark = "支付宝小程序")
    public static final String MP_ALIPAY = "210103";
    /**
     * 百度小程序
     */
    @DictionaryConfig(dictionaryName = "百度小程序", remark = "百度小程序")
    public static final String MP_BAIDU = "210104";
    /**
     * 头条小程序
     */
    @DictionaryConfig(dictionaryName = "头条小程序", remark = "头条小程序")
    public static final String MP_TOUTIAO = "210105";
    /**
     * 360小程序
     */
    @DictionaryConfig(dictionaryName = "360小程序", remark = "360小程序")
    public static final String MP_360 = "210106";
    /*==================小程序渠道================*/
}

因需对接多方不同渠道平台,故笔者先定义一套接口,制定规范。

package com.threeox.biz.account.platform.inter;

import com.threeox.biz.account.entity.AccountPlatformInfo;
import com.threeox.biz.account.platform.entity.AccessToken;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;
import com.threeox.biz.account.platform.entity.PhoneInfo;

/**
 * 开放平台接口
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/1/17 10:33
 */
public interface IOpenPlatform {


    /**
     * 获取手机信息
     *
     * @param params 授权登录的参数
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/23 23:13
     * @version 1.0
     */
    PhoneInfo getPhoneInfo(AuthorizedLoginParams params) throws Exception;

    /**
     * 获取三方平台对象
     *
     * @param params  授权登录的参数
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/22 23:29
     * @version 1.0
     */
    AccountPlatformInfo getOpenInfo(AuthorizedLoginParams params) throws Exception;

    /**
     * 获取授权凭证对象
     *
     * @param openPlatform
     * @return a
     * @author 赵屈犇
     * date 创建时间: 2022/6/25 00:44
     * @version 1.0
     */
    AccessToken getAccessToken(OpenPlatformConfigMessage openPlatform) throws Exception;

}

基于本接口实现基础的开发平台工厂类

package com.threeox.biz.account.platform.impl.base;

import com.threeox.biz.account.entity.AccountPlatformInfo;
import com.threeox.biz.account.platform.entity.AccessToken;
import com.threeox.biz.account.platform.entity.PhoneInfo;
import com.threeox.biz.account.platform.inter.IOpenPlatform;
import com.threeox.drivenlibrary.engine.config.DrivenEngineConfig;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.manage.cache.account.AccessTokenCacheManager;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;
import com.threeox.utillibrary.ConstUtils;
import com.threeox.utillibrary.date.DateUtil;
import com.threeox.utillibrary.date.TimeUtils;
import com.threeox.utillibrary.logger.LoggerFactory;
import com.threeox.utillibrary.strings.StringUtils;

/**
 * 基础开放平台类
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/1/16 11:39
 */
public abstract class BaseOpenPlatformFactory implements IOpenPlatform {

    /**
     * 日志对象
     */
    protected final LoggerFactory looger = LoggerFactory.getLogger(this.getClass().getName());

    @Override
    public PhoneInfo getPhoneInfo(AuthorizedLoginParams params) throws Exception {
        OpenPlatformConfigMessage openPlatform = getOpenPlatform(params);
        if (openPlatform != null) {
            return initPlatformPhoneInfo(params, openPlatform);
        }
        return null;
    }

    /**
     * 初始化平台手机信息
     *
     * @param params
     * @param openPlatform
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/23 23:18
     * @version 1.0
     */
    protected abstract PhoneInfo initPlatformPhoneInfo(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform) throws Exception;

    @Override
    public AccountPlatformInfo getOpenInfo(AuthorizedLoginParams params) throws Exception {
        // 根据应用渠道编码获取配置的开放渠道信息
        OpenPlatformConfigMessage openPlatform = getOpenPlatform(params);
        if (openPlatform != null) {
            AccountPlatformInfo platformInfo = new AccountPlatformInfo();
            platformInfo.setPlatformCode(params.getPlatformCode());
            platformInfo.setAppChannelCode(params.getAppChannelCode());
            // 子类实现三方平台账号主键获取
            initPlatformOpenId(params, openPlatform, platformInfo);
            return platformInfo;
        }
        return null;
    }

    /**
     * 设置三方平台账号主键
     *
     * @param params
     * @param openPlatform
     * @param platformInfo
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/22 23:54
     * @version 1.0
     */
    protected abstract void initPlatformOpenId(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform, AccountPlatformInfo platformInfo) throws Exception;

    /**
     * 获取开放平台配置信息
     *
     * @param params
     * @return a
     * @author 赵屈犇
     * date 创建时间: 2022/6/23 23:17
     * @version 1.0
     */
    protected OpenPlatformConfigMessage getOpenPlatform(AuthorizedLoginParams params) {
        // 根据应用渠道编码获取配置的开放渠道信息
        return DrivenEngineConfig.getInstance().getOpenPlatform(params.getAppChannelCode());
    }

    /**
     * 获取授权凭证对象
     *
     * @param openPlatform
     * @return a
     * @author 赵屈犇
     * date 创建时间: 2022/6/25 00:44
     * @version 1.0
     */
    @Override
    public AccessToken getAccessToken(OpenPlatformConfigMessage openPlatform) throws Exception {
        // 获取授权凭证缓存主键
        String accessCacheKey = getAccessCacheKey(openPlatform);
        if (StringUtils.isNotEmpty(accessCacheKey)) {
            AccessTokenCacheManager cacheManager = AccessTokenCacheManager.getInstance();
            // 获取缓存中的授权凭证
            AccessToken accessToken = cacheManager.get(accessCacheKey);
            if (accessToken == null) {
                // 调用子类获取
                accessToken = initAccessToken(openPlatform);
                if (accessToken != null) {
                    // 计算凭证失效时间
                    long expiresTime = TimeUtils.date2Millis(DateUtil.addSecond(TimeUtils.getNowTimeDate(), accessToken.getExpiresIn()));
                    accessToken.setExpiresTime(expiresTime);
                    // 缓存凭证
                    cacheManager.put(accessCacheKey, accessToken);
                }
                return accessToken;
            }
            if (accessToken != null) {
                // 计算凭证是否失效,防止凭证失效,但未清理情况
                long timeSpan = TimeUtils.getTimeSpanByNow(accessToken.getExpiresTime(), ConstUtils.TimeUnit.MSEC);
                // 此处为了避免失效过期等操作,小于一分钟都算失效
                if (timeSpan > 60000) {
                    return accessToken;
                }
                // 如果失效,清理缓存并重新获取
                cacheManager.remove(accessCacheKey);
                return getAccessToken(openPlatform);
            }
        }
        looger.warn("实现类正确配置获取授权凭证缓存主键!");
        return null;
    }

    /**
     * 获取授权凭证缓存主键,子类实现
     *
     * @param openPlatform
     * @return a
     * @author 赵屈犇
     * date 创建时间: 2022/6/25 01:02
     * @version 1.0
     */
    protected abstract String getAccessCacheKey(OpenPlatformConfigMessage openPlatform);

    /**
     * 子类实现初始化token
     *
     * @param openPlatform
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/25 00:56
     * @version 1.0
     */
    protected abstract AccessToken initAccessToken(OpenPlatformConfigMessage openPlatform) throws Exception;
}

本篇随笔,将实现微信小程序获取openid的封装,故而,以下为微信小程序基于父类的实现类。

在此之前,首先需要配置获取微信小程序openid的网络请求对象

package com.threeox.biz.account.config.request;

import com.threeox.biz.account.constants.AccountConstants;
import com.threeox.drivenlibrary.engine.annotation.base.ParamConfig;
import com.threeox.drivenlibrary.engine.annotation.request.NetWorkRequestConfig;
import com.threeox.drivenlibrary.engine.annotation.request.RequestConfig;
import com.threeox.drivenlibrary.engine.annotation.scan.RequestScanConfig;
import com.threeox.drivenlibrary.enums.dictionary.RequestMethod;

/**
 * 平台请求配置
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/23 00:07
 */
@RequestScanConfig
public class PlatformRequestConfig {

    /**
     * 获取微信授权凭证
     */
    @RequestConfig(requestName = "获取微信授权凭证", requestParam = {
            @ParamConfig(paramCode = "appid"),
            @ParamConfig(paramCode = "secret"),
            @ParamConfig(paramCode = "grant_type", paramValue = "client_credential"),
    }, netWorkConfig = @NetWorkRequestConfig(rootUrl = AccountConstants.WX_API_URL, serverUrl = "cgi-bin/token")
    )
    public static final String GET_WX_ACCESS_TOKEN = "COM.THREEOX.BIZ.ACCOUNT.CONFIG.REQUEST.PLATFORMREQUESTCONFIG.GET_WX_ACCESS_TOKEN";

    /**
     * 获取微信手机号码
     */
    @RequestConfig(requestName = "获取微信手机号码", requestParam = {
            @ParamConfig(paramCode = "access_token", valueCode = "token")
    }, netWorkConfig = @NetWorkRequestConfig(rootUrl = AccountConstants.WX_API_URL, methodType = RequestMethod.POST_TEXT, serverUrl = "wxa/business/getuserphonenumber",
            body = {
                    @ParamConfig(paramCode = "code")
            }
    ))
    public static final String GET_WX_PHONE_NUMBER = "COM.THREEOX.BIZ.ACCOUNT.CONFIG.REQUEST.PLATFORMREQUESTCONFIG.GET_WX_PHONE_NUMBER";

    /**
     * 获取微信openId
     */
    @RequestConfig(requestName = "获取微信openId", requestParam = {
            @ParamConfig(paramCode = "appid"),
            @ParamConfig(paramCode = "secret"),
            @ParamConfig(paramCode = "js_code", valueCode = "token"),
            @ParamConfig(paramCode = "grant_type", paramValue = "authorization_code")
    }, netWorkConfig = @NetWorkRequestConfig(rootUrl = AccountConstants.WX_API_URL, serverUrl = "sns/jscode2session")
    )
    public static final String GET_WX_OPEN_ID = "COM.THREEOX.BIZ.ACCOUNT.CONFIG.REQUEST.PLATFORMREQUESTCONFIG.GET_WX_OPEN_ID";


}

接下来具体实现对应的微信开放平台工厂功能

package com.threeox.biz.account.platform.impl.wx;

import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.account.config.AccountDictConfig;
import com.threeox.biz.account.config.annotation.PlatformExtend;
import com.threeox.biz.account.config.request.PlatformRequestConfig;
import com.threeox.biz.account.entity.AccountPlatformInfo;
import com.threeox.biz.account.platform.entity.AccessToken;
import com.threeox.biz.account.platform.impl.base.BaseOpenPlatformFactory;
import com.threeox.drivenlibrary.engine.constants.config.DrivenModelDBConstants;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.engine.request.execute.ExecuteRequestFactory;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;
import com.threeox.biz.account.platform.entity.PhoneInfo;
import com.threeox.httplibrary.entity.HttpResponseInfo;
import com.threeox.utillibrary.strings.StringUtils;

/**
 * 微信开放平台工厂
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/23 00:02
 */
@PlatformExtend(AccountDictConfig.PlatformType.MP_WEIXIN)
public class WxOpenPlatformFactory extends BaseOpenPlatformFactory {

    @Override
    protected void initPlatformOpenId(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform, AccountPlatformInfo platformInfo) throws Exception {
        // 调用配置好的获取微信openid的网络请求对象
        HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PlatformRequestConfig.GET_WX_OPEN_ID)
                .requestParam("appid", openPlatform.getWxAppId()).requestParam("secret", openPlatform.getWxAppSecret())
                .requestParam("token", params.getToken()).execute();
        if (responseInfo.isSuccess()) {
            JSONObject data = responseInfo.getData();
            if (data != null) {
                platformInfo.setPlatformOpenId(data.getString("openid"));
            }
        }
    }

    @Override
    protected PhoneInfo initPlatformPhoneInfo(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform) throws Exception {
        String wxPhoneCode = params.getWxPhoneCode();
        if (StringUtils.isNotEmpty(wxPhoneCode)) {
            AccessToken accessToken = getAccessToken(openPlatform);
            if (accessToken != null) {
                HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PlatformRequestConfig.GET_WX_PHONE_NUMBER).
                        requestParam("code", params.getWxPhoneCode()).requestParam("token", accessToken.getAccessToken())
                        .execute();
                if (responseInfo.isSuccess()) {
                    JSONObject data = responseInfo.getData();
                    if (data != null && "0".equals(data.getString("errcode"))) {
                        JSONObject phoneInfo = data.getJSONObject("phone_info");
                        return new PhoneInfo(phoneInfo.getString("purePhoneNumber"), phoneInfo.getString("countryCode"));
                    }
                }
            }
        }
        return null;
    }

    @Override
    protected String getAccessCacheKey(OpenPlatformConfigMessage openPlatform) {
        return openPlatform.getWxAppId();
    }

    @Override
    protected AccessToken initAccessToken(OpenPlatformConfigMessage openPlatform) throws Exception {
        // 调用配置好的获取微信openid的网络请求对象
        HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PlatformRequestConfig.GET_WX_ACCESS_TOKEN)
                .requestParam("appid", openPlatform.getWxAppId()).requestParam("secret", openPlatform.getWxAppSecret()).execute();
        if (responseInfo.isSuccess()) {
            JSONObject data = responseInfo.getData();
            if (data != null && data.containsKey("access_token")) {
                return new AccessToken(data.getIntValue("expires_in"), data.getString("access_token"));
            }
        }
        return null;
    }

}
package com.threeox.biz.account.platform.impl.wx;

import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.account.config.request.PlatformRequestConfig;
import com.threeox.biz.account.entity.AccountPlatformInfo;
import com.threeox.biz.account.platform.impl.base.BaseOpenPlatformFactory;
import com.threeox.drivenlibrary.engine.constants.config.DrivenModelDBConstants;
import com.threeox.drivenlibrary.engine.entity.driven.config.OpenPlatformConfigMessage;
import com.threeox.drivenlibrary.engine.request.execute.ExecuteRequestFactory;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;
import com.threeox.drivenlibrary.openplatform.entity.PhoneInfo;
import com.threeox.httplibrary.entity.HttpResponseInfo;
import com.threeox.utillibrary.strings.StringUtils;

/**
 * 微信开放平台工厂
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/23 00:02
 */
public class WxOpenPlatformFactory extends BaseOpenPlatformFactory {

    @Override
    protected void initPlatformOpenId(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform, AccountPlatformInfo platformInfo) throws Exception {
        // 调用配置好的获取微信openid的网络请求对象
        HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PlatformRequestConfig.GET_WX_OPEN_ID)
                .requestParam("appid", openPlatform.getWxAppId()).requestParam("secret", openPlatform.getWxAppSecret())
                .requestParam("token", params.getToken()).execute();
        if (responseInfo.isSuccess()) {
            JSONObject data = responseInfo.getData();
            if (data != null) {
                platformInfo.setPlatformOpenId(data.getString("openid"));
            }
        }
    }

    @Override
    protected PhoneInfo initPlatformPhoneInfo(AuthorizedLoginParams params, OpenPlatformConfigMessage openPlatform) throws Exception {
        String wxPhoneCode = params.getWxPhoneCode();
        if (StringUtils.isNotEmpty(wxPhoneCode)) {
            HttpResponseInfo responseInfo = ExecuteRequestFactory.builder().initConfig(DrivenModelDBConstants.DRIVEN_MANAGE_MODEL_DB_CODE, PlatformRequestConfig.GET_WX_PHONE_NUMBER).
                    requestParam("code", params.getWxPhoneCode()).requestParam("token", params.getToken())
                    .execute();
            if (responseInfo.isSuccess()) {
                JSONObject data = responseInfo.getData();
                if (data != null) {
                    return new PhoneInfo(data.getString("purePhoneNumber"), data.getString("countryCode"));
                }
            }
        }
        return null;
    }

}

至此,已实现了微信开放平台相关功能,笔者内置了获取授权凭证、手机号、开发主键对象。

其次,笔者准备提供api接口,在此,仍然使用笔者研发的框架配置授权登录接口。

package com.threeox.biz.account.api;

import com.threeox.drivenlibrary.engine.annotation.api.Api;
import com.threeox.drivenlibrary.engine.annotation.api.ApiVerifyConfig;
import com.threeox.drivenlibrary.engine.function.impl.AbstractApiExtend;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;

/**
 * 授权登录
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/23 23:08
 */
@Api(apiUrl = "authLogin", apiName = "授权登录", verifyConfigs = {
        @ApiVerifyConfig(paramCode = "platformCode", emptyHint = "请传入三方平台编码"),
        @ApiVerifyConfig(paramCode = "appChannelCode", emptyHint = "请传入应用渠道编码"),
}, isVerifyLogin = false, isVerifyToken = false, moduleUrl = "user")
public class AuthorizedLoginExtend extends AbstractApiExtend<AuthorizedLoginParams> {

    
}

至此,需再次梳理思路,考虑到后期的高扩展、高复用性,笔者预采用注解配置,配合反射扫描机制,动态绑定具体的三方渠道实现类。

在此,先定义扫描注解。

package com.threeox.biz.account.config.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 平台扫描配置
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/24 00:17
 */
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface PlatformExtend {

    /**
     * 数据字典扩展类
     * 
     * @return
     */
    String[] value() default {};

}

接下来,具体实现扫描的逻辑,因,之前已实现过其他扫描功能,故,此处只实现相关功能。

    /**
     * 初始化平台扩展实现类
     *
     * @param extendClass
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/6/24 00:22
     * @version 1.0
     */
    private void initPlatformExtend(Class extendClass) {
        boolean isPlatformExtend = extendClass.isAnnotationPresent(PlatformExtend.class);
        if (isPlatformExtend) {
            PlatformExtend extend = (PlatformExtend) extendClass.getAnnotation(PlatformExtend.class);
            String[] values = extend.value();
            for (String value : values) {
                try {
                    platformExtendCache.put(value, extendClass.newInstance());
                } catch (Exception e) {
                    logger.error("初始化平台扩展实现类报错", e);
                }
            }
        }
    }

    /**
     * 获取支付扩展类
     *
     * @param platformType
     * @return a
     * @author 赵屈犇
     * @date 创建时间: 2022/4/18 22:56
     * @version 1.0
     */
    public IPaymentFactory getPlatformExtend(String platformType) {
        return platformExtendCache.get(platformType);
    }

其次,之前实现的微信平台工厂类,声明注解并定义对应的类型

@PlatformExtend(AccountDictConfig.PlatformType.MP_WEIXIN)
public class WxOpenPlatformFactory extends BaseOpenPlatformFactory {
}

再者,在之前定义的授权登录接口中实现获取对应平台实现类相关代码。

package com.threeox.biz.account.api;

import com.alibaba.fastjson.JSONObject;
import com.threeox.biz.account.entity.AccountPlatformInfo;
import com.threeox.biz.account.platform.entity.PhoneInfo;
import com.threeox.biz.account.platform.inter.IOpenPlatform;
import com.threeox.dblibrary.executor.inter.ISqlExecutor;
import com.threeox.drivenlibrary.engine.ExtendFactory;
import com.threeox.drivenlibrary.engine.annotation.api.Api;
import com.threeox.drivenlibrary.engine.annotation.api.ApiVerifyConfig;
import com.threeox.drivenlibrary.engine.function.impl.AbstractApiExtend;
import com.threeox.drivenlibrary.engine.function.impl.AbstractUserExtend;
import com.threeox.drivenlibrary.engine.request.build.SqlBuilder;
import com.threeox.drivenlibrary.engine.request.inter.OnExecuteRequest;
import com.threeox.drivenlibrary.enums.ResponseResult;
import com.threeox.drivenlibrary.enums.dictionary.QueryType;
import com.threeox.drivenlibrary.manage.entity.params.AuthorizedLoginParams;
import com.threeox.drivenlibrary.manage.factory.user.UserFactory;
import com.threeox.utillibrary.java.IDGenerate;
import com.threeox.utillibrary.strings.StringUtils;

/**
 * 授权登录
 *
 * @author 赵屈犇
 * @version 1.0
 * @date 创建时间: 2022/6/23 23:08
 */
@Api(apiUrl = "login", apiName = "授权登录", verifyConfigs = {
        @ApiVerifyConfig(paramCode = "platformCode", emptyHint = "请传入三方平台编码"),
        @ApiVerifyConfig(paramCode = "appChannelCode", emptyHint = "请传入应用渠道编码"),
}, isVerifyLogin = false, isVerifyToken = false, moduleUrl = "user/authorized")
public class AuthorizedLoginExtend extends AbstractApiExtend<AuthorizedLoginParams> {

    @Override
    public boolean onBeforeApiExecute() throws Exception {
        AuthorizedLoginParams requestParams = getRequestParams();
        IOpenPlatform openPlatform = ExtendFactory.getInstance().getPlatformExtend(getParamValue("platformCode"));
        if (openPlatform != null) {
            // 获取手机号相关信息
            PhoneInfo phoneInfo = openPlatform.getPhoneInfo(requestParams);
            // 获取开放数据
            AccountPlatformInfo openInfo = openPlatform.getOpenInfo(requestParams);
            // 是否获取到开放平台主键
            boolean isOpenKey = openInfo != null && StringUtils.isNotEmpty(openInfo.getPlatformOpenId());
            if (phoneInfo == null && !isOpenKey) {
                responseResult(ResponseResult.AUTHOR_LOGIN_INCOMPLETE);
                return false;
            }
            // 判断手机号对象是否为空 存储手机号
            if (phoneInfo != null) {
                putRequestParam("accountPhone", phoneInfo.getPhoneNumber());
            }
            // 用户工厂类
            UserFactory userFactory = UserFactory.builder();
            // 设置处理用户处理类
            userFactory.setOnHandlerUser(new AbstractUserExtend() {
                @Override
                public void handlerSaveUser(String accountId, String userId, JSONObject requestParams, ISqlExecutor executor) throws Exception {
                    super.handlerSaveUser(accountId, userId, requestParams, executor);
                    // 未关联平台主键时存储
                    if (isOpenKey) {
                        openInfo.setId(IDGenerate.getId());
                        openInfo.setAccountId(accountId);
                        openInfo.save(executor);
                    }
                }
            });
            // 获取用户信息
            Object userInfo = userFactory.login((OnExecuteRequest<SqlBuilder>) builder -> {
                if (phoneInfo != null) {
                    builder.or("a", "account_phone", QueryType.EQUAL, phoneInfo.getPhoneNumber());
                }
                // 存在开放平台主键时关联
                if (isOpenKey) {
                    // 关联中间表
                    builder.joinBuilder().leftJoin("ox_Sys_Account_Platform", "p", "u.account_id = p.account_id");
                    // 关联查询字段
                    builder.orBracket("p", "platform_open_id", QueryType.EQUAL, openInfo.getPlatformOpenId())
                            .and("p", "platform_code", QueryType.EQUAL, openInfo.getPlatformCode())
                            .and("p", "app_channel_code", QueryType.EQUAL, openInfo.getAppChannelCode()).bracket();
                }
            });
            if (userInfo == null) {
                // 保存用户信息
                userInfo = userFactory.saveUser(getParams());
            }
            if (userInfo != null) {
                successResult("登录授权成功", userInfo);
            } else {
                responseResult(ResponseResult.AUTHOR_LOGIN_ERROR);
            }
        }
        return false;
    }
}

至此结尾,后期还会接入更多的三方平台账号体系。

诸君谨记,不积跬步,无以至千里;不积小流,无以成江海 。望诸君共勉。

猜你喜欢

转载自juejin.im/post/7115433526622683172