Java - 微信小程序授权手机号登录

        最近做了一个关于商城的项目,B端选用若依的开源框架,C端还是vue前后端分离。其中C端主要是小程序的形式,所以想着来总结一下对接微信小程序登录中Java部分遇到的坑即代码分享!

废话不多说,直接上代码!

1、controller 层代码

        入参我这边是直接使用request来接收,大家可以改成自己的DTO来接收入参

    @GetMapping("/letsLogin")
    @ApiOperation("微信授权登录")
    public R letsLogin(HttpServletRequest request){
        return remoteMallUserService.letsLogin(request);
    }

2、service 层代码

        其中涉及到几个基本配置参数,我这边单独列出,大家可以放入配置文件进行引用,也可以直接作为常量引用;

同时可以参考微信公众平台提供的开发文档(服务端):接口调用凭证 | 微信开放文档

// APP_ID 小程序注册时由微信提供 
private final static String APP_ID = "....";
// APP_SERCRET 小程序注册时由微信提供 
private final static String APP_SERCRET = ".....";
// 请求地址这边用了多个所以我们按照调用的顺序来说明
// 首先是这个TOKENURL 用于获取微信用户的授权认证 来拿到“accessToken”
private final static String TOKENURL = "https://api.weixin.qq.com/cgi-bin/token";
// 第二是用于请求获取用户手机号的地址(结尾的“access_token”需要拼接上TOKENURL返回的参数)
private final static String PHONENURL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
// 最后才是登录url了
private final static String URL = "https://api.weixin.qq.com/sns/jscode2session";

        由于我自身的业务中存在通过手机号验证登录这个功能模块,所以我在入参的时候会做一个是否存在手机号的判断,不存在时才通过微信去请求;存在时直接调用登录URL即可;

 这边还需要简单解释一下入参(红色为必传参数)

        1、userPhone  用户手机号;

        2、code:前端通过getPhoneNum() 获得的code;

        3、loginCode:前端通过wx.login() 获得的code;

@Autowired
    private RestTemplate restTemplate;

@Override
    public R letsLogin(HttpServletRequest request){
        // 先拿到前端通过wx.login()拿到的code -- 5分钟过期哦
        String loginCode = request.getParameter("loginCode");
        if(StringUtils.isBlank(loginCode)){
            return R.fail(101,"loginCode不可以为空!");
        }
        String userPhone = request.getParameter("userPhone");
        // 如果手机号为空则判断是否有code(该code是前端通过获取手机号方法拿到的)
        if (StringUtils.isBlank(userPhone)){
            String code = request.getParameter("code");
            if(StringUtils.isBlank(code)){
                return R.fail(101,"code为空,无法获取手机号!");
            }
            // 获取手机号 -- 这边需要定义一个传参的map
            Map<String, String> params1 = new HashMap<>();
            // 此处为固定值不需要修改
            params1.put("grant_type", "client_credential");  
            // APP_ID和APP_SERCRET需要根据实际情况进行传参
            params1.put("appid", APP_ID);  
            params1.put("secret", APP_SERCRET);
            // 调用TOKENURL获取授权凭证access_token
            // 我这边用的是Hultool的HTTP请求工具 -- 之后会附上maven依赖
            String resultToken = HttpUtil.sendGet(TOKENURL, params1);
            // fastjson 框架自带 大家可以选择自己的JSON转换工具
            JSONObject tokenJson = JSONObject.parseObject(resultToken);
            String accessToken = (String)tokenJson.get("access_token");
            // 使用前端code获取手机号码(accessToken一定要以get的方式请求)其他参数为json格式
            String url1 = PHONEURL + accessToken;
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("code", code);
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(paramMap, headers);
            ResponseEntity<Object> response = restTemplate.postForEntity(url1, httpEntity, Object.class);
            Object body = response.getBody();
            Map<String, Object> map = new ObjectMapper().convertValue(body, Map.class);
            Object phoneInfo = map.get("phone_info");
            Map<String, Object> map1 = new ObjectMapper().convertValue(phoneInfo, Map.class);
            // 以上都是response参数的处理 最终拿到userPhone 可以进行下一步 微信登陆了
            userPhone = (String)map1.get("phoneNumber");
        }

        // 构建 一个map传登录的参数
        Map<String, String> params = new HashMap<>();
        params.put("appid", APP_ID);
        params.put("secret", APP_SERCRET);
        // 这里的code是前端通过wx.login()获取到的
        params.put("js_code", loginCode); 
        // 固定参数
        params.put("grant_type", "authorization_code");
        String resultJson = HttpUtil.sendGet(URL, params);
        JSONObject json = JSONObject.parseObject(resultJson);
        if (!json.containsKey("errcode")) {
            // 拿到openid(用户在该小程序的唯一用户标识)
            String openId = (String)json.get("openid");

            // 之后的可以根据自己的业务进行处理 比如:新增用户...
            
            return R.ok("","登录成功");
        } else {
            return R.fail(101,"登录失败!");
        }
    }

3、util 层代码。添加一个RestTemplateConfig配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);//ms
        factory.setConnectTimeout(15000);//ms
        return factory;
    }
}

4、Hultool的依赖

     <!-- hutool 工具包-->
     <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.2.4</version>
     </dependency>

        最后说一下在开发中踩到的坑,就是获取手机号返回的response这边进行了两次的map转换才拿到最终的手机号,但是官方文档中的返回格式是一个JSON对象,如果是一个JSON串的话就不需要这么麻烦了,所以各位大神可以在开发的时候优化一下这部分!

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值