SpringCloud 大型系列课程正在制造中,欢迎大家重视与提意见。

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

  • SpringCloud 整合Gateway服务网关 【SpringCloud系列5】
  • SpringCloud 事务管理后台 经过FeignClient来调用oauth/token接口【SpringCloud系列11】
  • Spring Security OAuth2.0 多点登录与单点登录【SpringCloud系列12】
  • # SpringCloud 微信小程序授权登录 获取openId SessionKey【SpringCloud系列13】

本文章完成的是微信小程序获取微信绑定的手机号授权登录。

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

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

  • 方案一 只获取用户对应的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 服务中的微信认证接口。

SpringCloud 微信小程序 获取手机号一键登录 【SpringCloud系列14】
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);
}

然后在小程序中,当用户点击按钮获取手机号授权后,调用登录接口

SpringCloud 微信小程序 获取手机号一键登录 【SpringCloud系列14】
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 、英语相关的内容共享

本文正在参与「金石方案」