商务合作
首页 > 教程文章 > Java文章 > 正文

微信小程序登录-线上案例实战:springboot+vue

小程序的登陆流程,我们见这张图就好

下面我将根据这个流程,以实战代码讲解,请耐心阅读。


后端配置准备

引入小程序maven,其余springboot那些依赖我就不讲了。


        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>4.1.0</version>
        </dependency>

yml配置小程序信息:


wx:
  miniapp:
    configs:
      - appid: #微信小程序的appid
        secret: #微信小程序的Secret
        token: #微信小程序消息服务器配置的token
        aesKey: #微信小程序消息服务器配置的EncodingAESKey
        msgDataFormat: JSON

新增小程序配置类WxMaConfiguration:


@Configuration
@EnableConfigurationProperties(WxMaProperties.class)
public class WxMaConfiguration {

    @Autowired
    WxMaProperties properties;

    public static final Map<String, WxMaService> serviceList = Maps.newHashMap();


    public WxMaService getService(String appId) {
        if (serviceList.containsKey(appId)) {
            return serviceList.get(appId);
        }
        throw new RuntimeException("appId不存在");
    }

    @PostConstruct
    public void init() {
        List<WxMaProperties.Config> configs = this.properties.getConfigs();
        if (CollectionUtils.isEmpty(configs)) {
            throw new WxRuntimeException("请添加wx.miniapp 小程序信息配置!");
        }

        for (WxMaProperties.Config cfg : configs) {
            WxMaService maService = new WxMaServiceImpl();
            WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
            config.setAppid(cfg.getAppid());
            config.setSecret(cfg.getSecret());
            config.setToken(cfg.getToken());
            config.setAesKey(cfg.getAesKey());
            config.setMsgDataFormat(cfg.getMsgDataFormat());
            maService.setWxMaConfig(config);
            serviceList.put(cfg.getAppid(), maService);
        }
    }
}

属性文件WxMaProperties:


@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {

    private List<Config> configs;

    @Data
    public static class Config {
        /**
         * 设置微信小程序的appid
         */
        private String appid;

        /**
         * 设置微信小程序的Secret
         */
        private String secret;

        /**
         * 设置微信小程序消息服务器配置的token
         */
        private String token;

        /**
         * 设置微信小程序消息服务器配置的EncodingAESKey
         */
        private String aesKey;

        /**
         * 消息格式,XML或者JSON
         */
        private String msgDataFormat;
    }

}

到此基础配置信息就搞好了,我们还要准备两张表,一张是存储授权信息,一张是用户信息。


CREATE TABLE `user_info` (
  `user_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名',
  `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '密码',
  `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '电话',
  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '邮箱',
  `nick_name` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '昵称',
  `sex` smallint DEFAULT '0' COMMENT '性别. 0:未知;1:男;2:女',
  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '头像',
  `logout_time` timestamp NULL DEFAULT NULL COMMENT '最近登出时间',
  `creator` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updater` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '更新人',
  `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB COMMENT='用户信息';

CREATE TABLE `user_oauth` (
  `id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `user_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户ID',
  `openid` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `valid_status` smallint DEFAULT '1' COMMENT '有效状态. 1:有效;0:无效',
  `creator` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  `updater` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL,
  `update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=DYNAMIC COMMENT='授权信息';

用户表的字段根据你业务需要扩展。

前后端逻辑实现

  1. 前端发起wx登录获取code
uni.login({
	provider: 'weixin',
	success: function(loginRes) {
		// 前端获取到微信登录临时码,传至后台
		let code = loginRes.code
                // 调用后台接口根据code获取openid
		wxLogin(code).then((wxRes) => {
			resolve(wxRes)
		})
	},
})

2.前端调用后台login接口 ,传参:appId和code


// 请求后台微信小程序登录
export const wxLogin = (code) => {
	return new Promise((resolve) => { 
		let inviterUserId = getCurQuery('inviterUserId')
		console.debug(`调用微信小程序登录. inviterUserId=${inviterUserId || ''}`)
		post(`/core/user/login?loginType=WXMP`, {
			appid: config.appId,
			code: code
		}).then((res) => {
			console.log(res);
			if ('success' == res.status) {
                                console.debug('微信小程序登录成功')
			}
		})
	})
}

调用成功后,后端会返回openid 和 token信息,token是为了保持登录的。前端存储到本地,下次就直接登录成功。

3. 后端login接口


 public V login(LoginDTO dto) {
        String appid = (String) dto.getAppid();
        String code = (String) dto.getCode();

        if (StringUtils.isEmpty(appid) || StringUtils.isEmpty(code)) {
            return V.err("参数异常");
        }
        // 获取服务
        WxMaService service = wxMaConfiguration.getService(appid);
        WxMaJscode2SessionResult session = null;
        try {
            // 获取登录信息
            session = service.getUserService().getSessionInfo(code);
        } catch (WxErrorException e) {
            throw new RuntimeException("登录异常");
        }
        String openid = session.getOpenid();
        // 查询数据库信息
        UserOauth oauth = userOauthMapper.selectOne(new LambdaQueryWrapper<UserOauth>().eq(UserOauth::getValidStatus, 1)
                .eq(UserOauth::getLoginType, dto.getTyper()).eq(UserOauth::getOpenid, openid).last("limit 1"));
        if (oauth == null) {
            // 插入用户信息
            UserInfo user = new UserInfo();
            user.setUserId(IdUtil.getSnowflakeNextIdStr());// 主键
            user.setUsername("默认昵称_"+IdUtil.getSnowflakeNextIdStr());
            user.setNickName("默认昵称_"+IdUtil.getSnowflakeNextIdStr());
            userInfoMapper.insert(user) ;
            // 插入授权信息
            oauth = new UserOauth();
            oauth.setId(IdUtil.getSnowflakeNextIdStr());
            oauth.setUserId(user.getUserId());
            oauth.setLoginType(dto.getTyper());
            oauth.setOpenid(openid);
            oauth.setValidStatus(1);
            // 插入数据库
            userOauthMapper.insert(oauth);
        }
        // token登录
        StpUtil.login(oauth.getUserId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        Map<String,Object> ret = new HashMap<>();
        ret.put("tokenInfo" , tokenInfo) ;
        ret.put("openid" , openid) ;
        return V.success(ret);
    }

后端接口其实很简单,如果是第一次授权,openid在授权表中是没有的,就 插入授权信息,同时新增用户,然后在生成token(至于用什么框架生成自己选),然后将openid和token返回给前端。