SpringCloud 微信小程序 获取手机号一键登录 【SpringCloud系列14】

3,161 阅读3分钟

SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见。

本文章是系列文章中的一篇

本文章实现的是微信小程序获取微信绑定的手机号授权登录。 在这里插入图片描述

实现微信小程序用户登录的方案有三种,本文章实现的是第二种。

  • 方案一 只获取用户对应的openId,来创建标记用户
  • 方案二 获取用户对应的openId与微信绑定的手机来,来创建标记用户
  • 方案三 获取微信用户的基本信息,来创建标记用户。

1 微信小程序的登录页面

我这里只是放了一个登录按钮

<view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:20rpx;'>
  3. 同意当前小程序获取手机号;
  <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>
</view>

对应的页面 js

Page({

  /**
   * 页面的初始数据
   */
  data: {
    sessionKey:'',
    openId:'',
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    let that = this;
    wx.login({
      success: function (loginRes) {
         let code = loginRes.code;
         //获取sessionKey 
         wx.request({
          url: api.AuthLoginGetSessionKey,
          method: "post",
          header: {
            'appId': ''
          },
          data: {
            code: code,
          },
          success: function (res) {
            console.log('login success');
            let sessionKey = res.data.data.sessionKey;
            let openId = res.data.data.openId;
            that.setData({
              sessionKey: sessionKey,
              openId:openId
            });
          },
          fail: function (error) {
            //调用服务端登录接口失败
            console.log(error);
            wx.showModal({
              title: '提示',
              showCancel: false,
              content: '授权失败',
              success: function (res) {
                console.log(res)
                // 拒绝授权确定后到逻辑处理
                wx.navigateBack();
              }
            })
          }
        });
      },
      fail: function (err) {
        wx.showModal({
          title: '提示',
          showCancel: false,
          content: '授权失败',
          success: function (res) {
            console.log(res)
            // 拒绝授权确定后到逻辑处理
            wx.navigateBack();
          }
        })
      }
    });
  },


  getPhoneNumber: function (e) {
    var that = this;
    console.log(e.detail.errMsg == "getPhoneNumber:ok");
    if (e.detail.errMsg == "getPhoneNumber:ok") {
      wx.request({
        url: api.AuthLoginByPhone,
        method: "post",
        header: {
          'appId': 'wx27c83f987452ccec'
        },
        data: {
          encryptedData: e.detail.encryptedData,
          iv: e.detail.iv,
          sessionKey: that.data.sessionKey,
          openId: that.data.openId,
          uid: "",
        },
        method: "post",
        success: function (res) {
          console.log("res:", res)
          wx.setStorageSync('token', res.data.data.access_token);
          wx.setStorageSync('userInfo', res.data.data);
          console.log("token=" + res.data.data.access_token);
          wx.navigateBack();
        }
      })
    }
  },
})

这里实现获取手机号一键登录功能的步骤如下:

  • 第一步 进入页面时,获取临时登录令牌 code
  • 第二步 根据 code , 调用自己业务后接口,获取 openId 与 sessionKey
  • 第三步 页面中点击按钮获取微信绑定的手机号,这个需要用户触发
  • 第四步 获取手机号授权后,调用自己业务后台接口进行用户登录

2 业务后台

首先是根据code来获取sessionKey 与 openId , 这个接口是小程序中,用户在进入登录页面里直接调用的

@Slf4j
@RestController
@RequestMapping("/wx")
public class LoginController {

    @Resource
    private FeignWxClient feignWxClient;

    /**
     * @return sessionKey 与 openId 
     */
    @PostMapping(value = "/login_get_session")
    public CommonResult getSession(@RequestBody MiniLoginCodeRequest request, @RequestHeader String appId) {
        log.info("微信登录 port {}", serverPort);
        request.setAppId(appId);
        Map<String, Object> map = feignWxClient.miniLoginBySession(request);
        return CommonResult.success(map);
    }
}

如下图是本项目 微服务的调用关系,小程序统一访问 mini-api 服务,然后根据 code 去调用 wx-service 服务中的微信认证接口。 在这里插入图片描述 wx-service 服务用来处理微信登录、微信支付相关的内容,包括小程序的配置信息。 本文章使用到的 通过code 获取 openId 以及 sessionKey 相关描述 在《SpringCloud 微信小程序登录 方案一【SpringCloud系列13】》中有详述 FeignWxClient 的定义如下:

@FeignClient("wx-service")
public interface FeignWxClient {
    /**
     * 通过code 获取 openId 以及 sessionKey
     * @param loginDTO
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "/wx/login_by_code")
    Map<String,Object> miniLoginBySession(@RequestBody MiniLoginCodeRequest loginDTO);
}

然后在小程序中,当用户点击按钮获取手机号授权后,调用登录接口 在这里插入图片描述 wx-service 服务中解密电话

@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/wx")
public class WxUserController {


    @Autowired
    private WxAppLoginService wxAppLoginService;

    @ApiOperation(value = "获取用电话")
    @PostMapping("/login_by_phone")
    public Map<String,Object>  phone(@RequestBody MiniLoginRequest loginDTO) throws WxErrorException {
        return wxAppLoginService.phone(loginDTO);
    }
}

对应的 Service 实现类如下

@Service
@Slf4j
public class WxAppLoginServiceImpl implements WxAppLoginService {

    //查询数据库小程序配置
    @Autowired
    private WxAppInfoService wxAppInfoService;
    
    private WxMaService getWxMaService(String appId) {
        //查询数据库小程序的配置
        WxAppInfo wxAppInfo = wxAppInfoService.queryByAppId(appId);
        String appSecret = wxAppInfo.getSecret();

        WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
        config.setAppid(appId);
        config.setSecret(appSecret);
        config.setMsgDataFormat("JSON");
        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(config);
        return wxMaService;
    }

    @Override
    public Map<String, Object> phone(MiniLoginRequest loginDTO) {

        final WxMaService wxService = getWxMaService(loginDTO.getAppId());

        String iv = loginDTO.getIv();
        String encryptedData = loginDTO.getEncryptedData();
        String sessionKey = loginDTO.getSessionKey();

        // 解密
        WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
        Map<String, Object> map = new HashMap<>();
        map.put("phone", phoneNoInfo.getPhoneNumber());
        map.put("sessionKey", sessionKey);
        map.put("code", 200);
        return map;
    }
}

本项目 SpringCloud 源码 gitee.com/android.lon… 本项目 管理后台web 源码gitee.com/android.lon… 本项目 小程序 源码gitee.com/android.lon… 如果有兴趣可以关注一下公众号 biglead ,每周都会有 java、Flutter、小程序、js 、英语相关的内容分享

本文正在参加「金石计划」