一、登录流程

1.前端先通过wx.login获取用户登录临时凭证和getPhoneNumber接口获取手机号凭证,然后传给后端。
2.后端通过用户登录凭证调用微信接口可以得到openid,通过手机号凭证调取微信接口可以得到手机号。
3.然后通过openid查询数据库有没有,如果没有的话就新增,如果有的话就更新用户信息(如手机号、修改时间)。
4.生成令牌和昵称并响应给后端。

二、登录后端难点详解:得到手机号+openid

1.要想获取手机号 就要得到必须得请求参数access_token和手机号凭证Code 。

(1)得到access_token:通过GET请求https://api.weixin.qq.com/cgi-bin/token响应获取。

在这里插入图片描述

(2)手机号凭证Code: 通过前端的bindgetphonenumber方法获取然后传入后端的

2.得到获取手机号:通过POST 请求 https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=xxx 获取。

在这里插入图片描述

3.获取openid :通过GET请求https://api.weixin.qq.com/sns/jscode2session获取。

在这里插入图片描述

三、主要核心代码如下:

package com.zzyl.service.impl;

import cn.hutool.http.*;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zzyl.dto.MemberDto;
import com.zzyl.entity.Member;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.MemberMapper;
import com.zzyl.service.MemberService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class MemberServiceImpl implements MemberService {
    @Autowired
    private MemberMapper memberMapper;
    @Value("${wx.appid}")
    private  String appid;
    @Value("${wx.secret}")
    private  String secret;
    private static final String BASE_URL = "https://api.weixin.qq.com";

    @Override
    public LoginVo login(MemberDto dto) {
//        1.获取oppenid
        String openId = getOpenid(dto.getCode());
//        2.获取手机号凭证
        String accessToken = getAccessToken();
//        3.获取手机号
        String phone = getPhone(dto.getPhoneCode(), accessToken);
//        4.根据openid查询数据库  如果有的话就修改手机号, 没有就新增
        Member member = null;
        try {
            member = memberMapper.selectByOpenId(openId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (StringUtils.isNull(member)) {
                String name = "微信用户" + phone.substring(7);
//               builder是简化对象的构建过程,可以理解为多参构造器
                member = Member.builder()
                        .openId(openId)
                        .phone(phone)
                        .name(name).build();
                memberMapper.insert(member);
            } else {
                member.setPhone(phone);
                memberMapper.update(member);
            }

//        5.登录成功设置令牌
        LoginVo loginVo = new LoginVo();
        Map<String, Object> clams = new HashMap<>();
        try {
            clams.put("id", member.getId());
            clams.put("name", member.getName());
            String token = JwtUtil.createJWT(secret, 24, clams);
            loginVo.setToken(token);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.SYSYTEM_FAIL);
        }
        loginVo.setNickName(member.getName());
        return loginVo;
    }

    /**
     * 获取手机号令牌token
     * @return
     */
    private String getAccessToken() {
        String url = "/cgi-bin/token";
        Map<String, Object> params = new HashMap<>();
        params.put("grant_type", "client_credential");
        params.put("appid", appid);
        params.put("secret", secret);
        String token = null;
        try {
            String resStr = HttpUtil.get(BASE_URL + url, params);
            token = (String) JSONUtil.parseObj(resStr).get("access_token");
        } catch (Exception e) {
            throw new BaseException(BasicEnum.GET_TOKEN_ERROR);
        }
        return token;
    }
    /**
     * 获取手机号
     * @param phoneCode    手机号获取凭证(前端登录传入的)
     * @param accessToken 手机号接口调用凭证
     * @return
     */
    private String getPhone(String phoneCode, String accessToken) {
        String url = "/wxa/business/getuserphonenumber";
        Map<String, Object> bodys = new HashMap<>();
        bodys.put("code", phoneCode);
        String phone = null;
        try {
            HttpRequest request = HttpUtil.createRequest(Method.POST, BASE_URL + url+"?access_token="+accessToken);
            request.body(JSONUtil.toJsonStr(bodys));
            HttpResponse response = request.execute();
            String resStr =response.body();
            Object phoneInfo = JSONUtil.parseObj(resStr). get("phone_info");
            phone = JSONUtil.parseObj(phoneInfo).getStr("phoneNumber");
            return phone;
        } catch (Exception e) {
            throw new BaseException(BasicEnum.GET_PHONE_ERROR);
        }

    }
    /**
     * 根据code获取用户在小程序的唯一标识
     *
     * @param code
     * @return
     */
    private String getOpenid(String code) {
        String url = "/sns/jscode2session";
        Map<String, Object> params = new HashMap<>();
        params.put("appid", appid);
        params.put("secret", secret);
        params.put("js_code", code);
        params.put("grant_type", "authorization_code");
        JSONObject resObj = null;
        Object errcode = null;
        try {
            HttpRequest request = HttpUtil.createRequest(Method.POST, BASE_URL + url).form(params);
            HttpResponse response = request.execute();
            resObj = JSONUtil.parseObj(response.body());
            errcode = resObj.get("errcode");
        } catch (HttpException e) {
            throw new BaseException(BasicEnum.SYSYTEM_FAIL);
        }
        log.info("resObj: {}", resObj);
        if (errcode != null) {
            throw new BaseException(BasicEnum.GET_OPENID_ERROR);
        }
        return (String) resObj.get("openid");
    }
}

相关链接:微信小程序实现手机号一键登录(小程序原生代码实现)

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐