SpringBoot 小程序绑定微信登录

注:这个示例主要是我项目中小程序需要对接微信登录以获取用户的手机号为前提开发的登录接口,大家根据自己的业务需求来参考哈!

步骤分析:

小程序端–》调用wx.login()获取code,就是授权码。注意一个授权码只能使用一次。

小程序端–》调用wx.request()发送请求并携带code,请求开发者服务器(自己编写的后端服务)。

开发者服务端–》通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数。

开发者服务端–》接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识。

开发者服务端–》自定义登录态,生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验。

小程序端–》收到自定义登录态,存储storage。

小程序端–》后绪通过wx.request()发起业务请求时,携带token。

开发者服务端–》收到请求后,通过携带的token,解析当前登录用户的id。

开发者服务端–》身份校验通过后,继续相关的业务逻辑处理,最终返回业务数据。

1.首先微信小程序申请时会有一个appid 这是小程序的唯一ID需要用到的,还有一个小程序secret密钥也是请求微信API是需要用到的参数。

服务端开发者要做的:

1.接收小程序的code
2.通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数
3.接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识。到现在就获得了小程序用户的唯一标识opendId,接下来要验证这个用户是否是新用户,若是则新增一条用户信息存入数据库。
4.生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验
5.之后小程序端发出的所有请求都必须携带toke,解析用户ID进行后续的业务调用

2.调用微信的API(具体业务的调用方法参考微信小程序官方文档进行查看调阅)

package com.huixin.security.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Component
public class WeChatUtil {

	private static String appletAppId = "wx........"; // 小程序appid
	private static String appletSecret = "2a..............."; // 小程序secret
	private static long appletTime = 5400; // 小程序accessToken过期时间,官方是2小时,此处设定为1个半小时

	private static final Logger logger = LoggerFactory.getLogger(WeChatUtil.class);

	/**
	 * @date: 2024年4月2日 上午11:03:35
	 * @Description: 获取小程序 openid
	 */
	public static JSONObject getOpenid(String jsCode) {
		String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appletAppId + "&secret="
				+ appletSecret + "&js_code=" + jsCode + "&grant_type=authorization_code";

		JSONObject jsonObject = JSON.parseObject(URLConnectionUtil.sendGet(requestUrl));
		return jsonObject;
	}

	/**
	 * @date: 2024年4月2日 上午10:38:08
	 * @Description: 获取小程序access_token
	 */
	public static JSONObject getAccessToken() {
		// 从redis获取,如果没有则从微信获取
		String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appletAppId
				+ "&secret=" + appletSecret;

		String accessToken = URLConnectionUtil.sendGet(url);

		JSONObject jsonObject = JSON.parseObject(accessToken);
		return jsonObject;
	}

	/**
	 * @date: 2024年4月2日 下午1:00:14
	 * @Description: 获取电话
	 */
	public static JSONObject getPhone(String code, String accessToken) {
		String requestUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;

		JSONObject params = new JSONObject();
		params.put("code", code);

		JSONObject jsonObject = JSON.parseObject(URLConnectionUtil.sendPost(requestUrl, params));
		return jsonObject;
	}

	/**
	 * @date: 2024年4月23日 下午5:13:12
	 * @Description: 获取Openlink
	 */
	public static JSONObject getOpenlink(String accessToken, JSONObject parameter) {
		String requestUrl = "https://api.weixin.qq.com/wxa/generatescheme?access_token=" + accessToken;

		JSONObject jsonObject = JSON.parseObject(URLConnectionUtil.sendPost(requestUrl, parameter));
		return jsonObject;
	}
}

3.小程序绑定微信登录

package com.huixin.security.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSONObject;
import com.huixin.security.utils.*;
import com.huixin.security.vo.UserCodeVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.huixin.security.common.RespBean;
import com.huixin.security.constant.Constant;
import com.huixin.security.dao.UserDao;
import com.huixin.security.model.User;

@Service
public class LoginService {

	@Resource
	private UserDao userDao;

	@Autowired
	private PasswordEncoder passwordEncoder;

	@Autowired
	private JwtTokenUtil jwtTokenUtil;

	@Autowired
	RedisUtil redisUtil;

	@Value("${login.check}")
	private boolean loginCheck;


	public RespBean bindWeChat(JSONObject parameter) {
		String code = parameter.getString("wxCode"); // 前端生成code获取open ID
		String codePhone = parameter.getString("phoneCode");//获取电话信息的code
		String openid = ""; // 前端传递来的openid

		// 获取openid
		JSONObject openidJson = WeChatUtil.getOpenid(code);
		if (openidJson != null && openidJson.containsKey("openid")) {
			openid = openidJson.getString("openid");
		} else {
			return RespBean.error("微信获取openid失败!");
		}

		// 获取access_token
		JSONObject accessTokenJson = WeChatUtil.getAccessToken();
		String accessToken = "";
		if (null != accessTokenJson && !accessTokenJson.toString().equals("")) {
			accessToken = accessTokenJson.getString("access_token");
		} else {
			return RespBean.error("微信获取access_token失败!");
		}

		// 获取手机号
		JSONObject phoneJson = WeChatUtil.getPhone(codePhone, accessToken);
		if (null != phoneJson && !phoneJson.toString().equals("")) {
			Map<String, Object> phoneInfo = (Map<String, Object>) phoneJson.get("phone_info");
			if (null == phoneInfo) {
				return RespBean.error("微信获取电话号码失败!");
			}
			String phoneNumber = (String) phoneInfo.get("phoneNumber");

			// 检查用户是否存在
			User user = userDao.getUserByMobile(phoneNumber);
			if (user != null && user.getState()==Constant.PAGENUM) {
				// 用户存在,更新用户的openid
				user.setOpenid(openid);
				userDao.editUserOpenid(user);
			} else {
				// 用户不存在,创建新用户
				user = new User();
				user.setMobile(phoneNumber);
				user.setOpenid(openid);
				user.setUsername(phoneNumber); // 可根据需要自定义用户名
				user.setPassword(passwordEncoder.encode(UuidUtil.getUuid()));
				user.setState((byte) Constant.PAGENUM); // 设置用户状态
				user.setRole("1");
				user.setId(UuidUtil.getUuid());
				userDao.savaUser(user); // 保存新用户
				//新增userinfo数据
				User user1=new User();
				user1.setId(UuidUtil.getUuid());
				user1.setMobile(phoneNumber);
				user1.setOpenid(user.getId());
				userDao.addUserInfo(user1);
			}

			// 更新用户登录信息
			userDao.editUserLogininfo(user.getId());

			UserDetail userDetail = new UserDetail();
			userDetail.setUsername(user.getUsername());
			// 获取权限
			Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
			//获取最新的用户信息
			user = userDao.getUserByUsername(phoneNumber);
			// 更新security登录用户对象
			UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
					user, null, grantedAuthorities);
			// 使用jwt时,需要把登录信息放到redis里判断登录信息
			redisUtil.set(userDetail.getUsername()+Constant.USER_INFO_REDIS_SUFFIX, usernamePasswordAuthenticationToken,
					Constant.LOGIN_EFFECTIVE_TIME);

			String token = jwtTokenUtil.generateToken(userDetail);

			Map<String, Object> map = new HashMap<>();
			map.put("token", token);
			map.put("tokenHead", jwtTokenUtil.getTokenHead());
			map.put("phone", phoneNumber);
			return RespBean.ok("登录成功!", map);
		} else {
			return RespBean.error("微信获取电话号码失败!");
		}
	}

}

(我这里的逻辑是如果该微信用户不是小程序的用户时去微信获取该用户的信息添加到小程序中,后面直接给前端返回登录成功的token信息登录。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值