Java 实现App整合第三方微信登录

一、前期准备

对于微信登录来说,我们需要先取注册开发者账号
登录 https://open.weixin.qq.com/,并在管理中心—移动应用中创建我们的应用。然后点击查看就可以看到属于我们的一个AppID和AppSecret。
在这里插入图片描述

二、数据库设计

为了整合第三方的登录所以我们需要新建一张表,此时我们本身肯定就有一张用户表其中包括user_id、password等字段。这时我们需要再建一张用户认证信息表来存放认证信息。大致包括以下几个字段

字段名描述
id自增
user_id关联用户表中的user_id
third_type第三方平台类型 wx、qq等
third_key第三方平台的用户唯一标识,微信可以使用openid或unionid
create_time创建时间

三、实现思路

先说一个通用的思路再对微信的操作进行详细展开。

  1. 首先app端调取用户授权,用户同意授权后返回一个用户在第三方平台的唯一标识
  2. 将取到的唯一标识放到用户认证信息表user_auth中去查询,如果没有查到就说明用户是第一次登录,那么就在user表中创建一个新用户并获取到user_id。将user_id和唯一标识存到user_auth表中。如果用户认证信息表中已经查询到了结果,那么我们就利用查询结果中的user_id,再去user表中进行查询获取用户的相关信息。

四、微信实现

4.1 实现流程
  1. app端调取用户授权页面,获取一个code并传给后端
  2. 后端利用code、appid、appsecret调取微信的接口获取access_token以及openid
  3. 利用access_token和openid就可以获取到微信用户的相关信息
    如下所示为微信官方给出的时序图:
    在这里插入图片描述
4.2 微信接口说明
4.2.1 通过 code 获取 access_token
//请求说明
GET https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

在这里插入图片描述

{
  "access_token": "ACCESS_TOKEN",
  "expires_in": 7200,
  "refresh_token": "REFRESH_TOKEN",
  "openid": "OPENID",
  "scope": "SCOPE"
}

在这里插入图片描述

4.2.2 获取用户个人信息(UnionID 机制)

此接口用于获取用户个人信息。开发者可通过 OpenID 来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的 unionid 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的 unionid 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid 是相同的。请注意,在用户修改微信头像后,旧的微信头像 URL 将会失效,因此开发者应该自己在获取用户信息后,将头像图片保存下来,避免微信头像 URL 失效后的异常情况。

//请求说明
GET https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID

在这里插入图片描述

{
  "openid": "OPENID",
  "nickname": "NICKNAME",
  "sex": 1,
  "province": "PROVINCE",
  "city": "CITY",
  "country": "COUNTRY",
  "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
  "privilege": ["PRIVILEGE1", "PRIVILEGE2"],
  "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

在这里插入图片描述

五、代码实现

接口实现类代码如下

@Override public UserInfo weChatLogin(String code) {
        try {
            //根据code获取 access_token信息
            JSONObject jsonObject = AuthUtil.getAccessToken(code);
            if(jsonObject.containsKey("access_token")){
                String accessToken = jsonObject.getString("access_token");
                String openid = jsonObject.getString("openid");

                UserInfo userInfo = new UserInfo();
                // 判断用户是否注册过
                UserAuths userAuths = userAuthsMapper.selectByThirdKey("wx",openid);
                if (userAuths == null){
                    // 开始用户注册
                    // 根据token和openid获取用户的信息
                    JSONObject userInfoJsonObject = AuthUtil.getUserInfo(accessToken,openid);
                    if(userInfoJsonObject.containsKey("unionid")){
                        WXUserInfoVO wxUserInfo = userInfoJsonObject.toJavaObject(WXUserInfoVO.class);
                        userInfo.setNickname(wxUserInfo.getNickname());
                        userInfo.setName(wxUserInfo.getNickname());
                        userInfo.setGender(wxUserInfo.getSex());
						userInfo.setAvatar(wxUserInfo.getHeadimgurl());
                        userInfoMapper.insertUserInfoSelective(userInfo);
                        Long userId = userInfo.getUserId();
                        if (userId == null) {
                            throw new ServiceException("用户基本信息注册失败");
                        }
						// 添加用户认证信息
						userAuths = new UserAuths();
                        userAuths.setUserId(userId);
                        userAuths.setThirdKey(openid);
                        userAuths.setThirdType("wx");
                        userAuthsMapper.insertSelective(userAuths);
                    }else {
                        logger.error("查询微信用户信息接口调用失败");
                    }
                }else {
                    // 根据用户id查询用户的信息
                    List<UserInfo> userInfoList = userInfoMapper.selectUserInfoByUserId(userAuths.getUserId());
                    if(userInfoList.size() > 0){
                        userInfo = userInfoList.get(0);
                    }
                }

            }else {
                logger.error("查询accessToken接口调用失败");
            }

        } catch (Exception e) {
            throw new ServiceException("用户登录失败");
        }
        return userInfo;
    }

工具类代码如下

package com.youngmaker.userservice.utils;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.http.*;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;

@Slf4j
public class AuthUtil {
    public static final String APPID = "xxxxxxxxxxxx";
    public static final String APPSECRET = "xxxxxxxxxxxxxxxxxxxx";

    /**
     * @Title: getAccessToken
     * @Description: 获取接口调用凭证
     * @param: @return
     * @return: String
     */
    public static JSONObject getAccessToken(String code) {
        RestTemplate restTemplate = new RestTemplate();
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + AuthUtil.APPID + "&secret=" + AuthUtil.APPSECRET + "&code=" + code
                + "&grant_type=authorization_code";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> entity = new HttpEntity<String>(headers);
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
        String body = responseEntity.getBody();
        // 返回结果转换为json对象
        JSONObject jObject = JSONObject.parseObject(body);
        return jObject;
    }

    public static JSONObject getUserInfo(String accessToken, String openid) {
        RestTemplate restTemplate = new RestTemplate();
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
        HttpEntity<String> entity = new HttpEntity<String>(headers);
        String body = restTemplate.exchange(url, HttpMethod.GET, entity, String.class).getBody();
        // 返回结果转换为json对象
        JSONObject jObject = JSONObject.parseObject(body);
        return jObject;
    }
  

微信用户信息实体类

package com.youngmaker.userservice.VO.request.user;

import java.util.List;

public class WXUserInfoVO {

    private String openid;
    private String nickname;
    private int sex;
    private String province;
    private String city;
    private String country;
    private String headimgurl;
    private String unionid;
    private List<String> privilege;

    public String getOpenid() {
        return openid;
    }

    public void setOpenid(String openid) {
        this.openid = openid;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public int getSex() {
        return sex;
    }

    public void setSex(int sex) {
        this.sex = sex;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getHeadimgurl() {
        return headimgurl;
    }

    public void setHeadimgurl(String headimgurl) {
        this.headimgurl = headimgurl;
    }

    public String getUnionid() {
        return unionid;
    }

    public void setUnionid(String unionid) {
        this.unionid = unionid;
    }

    public List<String> getPrivilege() {
        return privilege;
    }

    public void setPrivilege(List<String> privilege) {
        this.privilege = privilege;
    }
}

用户信息实体类就根据自己的具体情况写了,这里就不放具体的代码了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值