利用 HttpClient 实现小程序微信登录功能

利用 HttpClient 实现小程序微信登录功能

1、HttpClient

1)Why HttpClient?

微信登录实现流程

要为我们的小程序实现微信登录功能,可以参考微信官方提供的官方文档来实现。开放能力 / 用户信息 / 小程序登录 (qq.com)
下面来看一下官方文档中小程序实现登录功能的流程:

img

分析
  1. 通过 wx.login() 接口来获得登录凭证(code)。
  2. 将登录凭证传递给后端服务器
  3. 后端服务器通过向微信接口服务发送请求,请求中包含
属性类型必填说明
appidstring小程序 appId
secretstring小程序 appSecret
js_codestring登录时获取的 code,可通过wx.login获取
grant_typestring授权类型,此处只需填写 authorization_code
  1. 通过这个请求,我们就能换取 用户唯一标识 OpenID 、 用户在微信开放平台账号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台账号) 和 会话密钥 session_key。
  2. 这时候我们就能对用户信息进行处理,比如将用户存入数据库或者利用这些信息来构建 token 返回给前端等
  3. 用户继续使用服务
什么是 openID 和 unionID

openID:
微信小程序的开发过程中,往往需要将用户信息录入自己的数据库中,就得有一个唯一标记区分用户,这个标记就是openid。当一个用户使用了某个微信小程序,微信后台会产生一个openid,并且是唯一的,所以可以通过这个来区分用户。

unionID:
如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

HttpClient

了解了上面的登录流程,了解到我们需要想想微信提供的服务接口发送请求来获取用户的标识,这时候就需要通过 Java 来向 code2Session 接口发送符合规范的请求,尽管 Java 原生的方式(如使用 HttpURLConnection)也可以执行 HTTP 请求,但通常情况下,HttpClient 更适合需要更高级功能和更好性能的应用程序。在大多数情况下,使用 HttpClient 可以更快速地构建可维护和高性能的 HTTP 客户端。

2)Quick Start

先来看看官方为我们提供的示例文档中的方法

	// 构建 HttpClient 对象
	CloseableHttpClient httpclient = HttpClients.createDefault();

	// 实现 get 请求
    ClassicHttpRequest httpGet = ClassicRequestBuilder.get("http://httpbin.org/get")
    httpclient.execute(httpGet, response -> {
        final HttpEntity entity1 = response.getEntity();
        EntityUtils.consume(entity1);
        return null;
    }
        
	// 实现 post 请求
    ClassicHttpRequest httpPost = ClassicRequestBuilder.post("http://httpbin.org/post")
            .setEntity(new UrlEncodedFormEntity(Arrays.asList(
                    new BasicNameValuePair("username", "vip"),
                    new BasicNameValuePair("password", "secret"))))
            .build();
    httpclient.execute(httpPost, response -> {		
        System.out.println(response.getCode() + " " + response.getReasonPhrase());
        final HttpEntity entity2 = response.getEntity();
        EntityUtils.consume(entity2);
        return null;
    }

​ 上述的操作为我们演示了如何实现 get 和 post 请求的发送

使用步骤

根据上面的示例,我们来总结一下这个 Java 库的基础的使用步骤:

  1. 引入依赖

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    
  2. 创建 HttpClient 实例

    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    
    CloseableHttpClient httpClient = HttpClients.createDefault();
    
    
  3. 创建一个 HTTP 请求对象,根据自己的需求来创建一个 GET 或者 POST 对象

    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    
    HttpGet httpGet = new HttpGet("https://www.example.com");
    HttpPost httpPost = new HttpPost("https://www.example.com");
    
  4. 设置请求参数:可以设置请求头、请求体、超时时间等参数

    httpGet.addHeader("User-Agent", "MyHttpClient");
    httpPost.addHeader("Content-Type", "application/json");
    
    // 设置请求体
    httpPost.setEntity(new StringEntity("{'key': 'value'}"));
    
  5. 执行请求:使用 HttpClient 执行请求,得到响应对象

    CloseableHttpResponse response = httpClient.execute(httpGet);
    
  6. 处理响应

    int statusCode = response.getStatusLine().getStatusCode;
    HttpEntity entity = response.getEntity;
    String responseContent = EntityUtils.toString(entity);
    
  7. 释放资源:最后,不要忘记释放 HttpClient 和响应对象的资源,以防止资源泄漏:

    response.close();
    httpClient.close();
    

2、实现微信登录功能

当我们向这个接口发送请求的时候,接口会向我们返回如下的结果:

属性类型说明
session_keystring会话密钥
unionidstring用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台账号下会返回,详见 UnionID 机制说明
errmsgstring错误信息
openidstring用户唯一标识
errcodeint32错误码

为了避免对 HttpClient 代码的反复调用,我们可以封装一个工具类来完成请求的发送和结果的接受,我们只需要获得需要的参数即可,将实现微信登录分为以下的步骤:

  1. 构建一个工具类来发送请求和接收结果,这个工具类中我们通过向里面传入一个请求地址,和参数图来实现请求的发送。

    /**
     * Http工具类
     */
    public class HttpClientUtil {
    
        static final  int TIMEOUT_MSEC = 5 * 1000;
    
        /**
         * 发送GET方式请求
         * @param url
         * @param paramMap
         * @return
         */
        public static String doGet(String url,Map<String,String> paramMap){
            // 创建Httpclient对象
            CloseableHttpClient httpClient = HttpClients.createDefault();
    
            String result = "";
            CloseableHttpResponse response = null;
    
            try{
                URIBuilder builder = new URIBuilder(url);
                if(paramMap != null){
                    for (String key : paramMap.keySet()) {
                        builder.addParameter(key,paramMap.get(key));
                    }
                }
                URI uri = builder.build();
    
                //创建GET请求
                HttpGet httpGet = new HttpGet(uri);
    
                //发送请求
                response = httpClient.execute(httpGet);
    
                //判断响应状态
                if(response.getStatusLine().getStatusCode() == 200){
                    result = EntityUtils.toString(response.getEntity(),"UTF-8");
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                try {
                    response.close();
                    httpClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return result;
        }
    }
    
  2. 利用工具类来发送请求

     	// 微信用于接收传输来数据的接口,作为 GET 请求的 url 使用
         public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    	/**
         * 微信登录
         * @param userLoginDTO 接受微信登录的信息的对象
         * @return UserLoginVO
         */
        @PostMapping("/login")
        @ApiOperation("微信用户登录的实现")
        public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
            log.info("微信用户登录{}", userLoginDTO);
    
            // 微信登录
            User user = userService.wxLogin(userLoginDTO);
    
            //为微信用户生成登录的令牌
            Map<String, Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.USER_ID, user.getId());
            String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
    
            UserLoginVO userLoginVO = UserLoginVO.builder()
                    .id(user.getId())
                    .openid(user.getOpenid())
                    .token(token)
                    .build();
            return Result.success(userLoginVO);
        }
    

    这里使用 JWT 来实现对用户的验证,不了解的可以看一下我的这篇文章JWT 详解与使用方法-CSDN博客

        public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
        @Override
        public User wxLogin(UserLoginDTO userLoginDTO) {
            // 调用接口服务获得 openid,具体方法实现在下方
            String openid = getOpenid(userLoginDTO.getCode());
    
            // 判断 openid 是否为空,为空则登录失败,抛出异常
            if (openid == null) {
                throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
            }
    
            // 判断用户是否是新用户
            User user = userMapper.getByOpenId(openid);
    
            if (user == null) {
                user = User.builder()
                        .openid(openid)
                        .createTime(LocalDateTime.now())
                        .build();
                userMapper.insert(user);
            }
            // 如果是新用户则自动完成注册,向用户数据库中插入对象
            return user;
        }
    
    /**
         * 得到 openid 的方法
         * @param code
         * @return
         */
        private String getOpenid(String code) {
            Map<String, String> map = new HashMap<>();
            map.put("appid", weChatProperties.getAppid());
            map.put("secret", weChatProperties.getSecret());
            map.put("js_code", code);
            map.put("grant_type", "authorization_code");
            String json = HttpClientUtil.doGet(WX_LOGIN, map);
            JSONObject jsonObject = JSON.parseObject(json);
            return jsonObject.getString("openid");
        }
    

​ 根据微信官方提供的需要的参数的文档,我们来为 Map 对象中注入 k-v 对象,这个对象在传入工具类后会通过解析然后作为构建 uri 的元素。
​ 这个工具类会将 JSON 字符串转为 Sting 字符串来返回,这时候我们为了可以得到其中的元素就需要将其转为然后通过 fastjson 提供的方法来得到对象中的元素。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

*Soo_Young*

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值