All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gitlab.summercattle.addons.wechat.miniprogram.service.impl.MiniProgramServiceImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitlab.summercattle.addons.wechat.miniprogram.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.gitlab.summercattle.addons.wechat.auth.service.UserService;
import com.gitlab.summercattle.addons.wechat.bind.BindUserInfo;
import com.gitlab.summercattle.addons.wechat.common.AppType;
import com.gitlab.summercattle.addons.wechat.common.MiniProgramUserSession;
import com.gitlab.summercattle.addons.wechat.common.AbstractUserSession;
import com.gitlab.summercattle.addons.wechat.common.service.WeChatService;
import com.gitlab.summercattle.addons.wechat.constants.WeChatConstants;
import com.gitlab.summercattle.addons.wechat.memory.SessionMemoryService;
import com.gitlab.summercattle.addons.wechat.miniprogram.bind.UserPhoneNumberBindHandle;
import com.gitlab.summercattle.addons.wechat.miniprogram.configure.MiniProgramConfigProperties;
import com.gitlab.summercattle.addons.wechat.miniprogram.configure.MiniProgramApplication;
import com.gitlab.summercattle.addons.wechat.miniprogram.service.MiniProgramService;
import com.gitlab.summercattle.addons.wechat.miniprogram.service.UserEncryptKeyInfo;
import com.gitlab.summercattle.addons.wechat.store.UserBindInfo;
import com.gitlab.summercattle.addons.wechat.store.UserBindStoreService;
import com.gitlab.summercattle.addons.wechat.utils.ApplicationUtils;
import com.gitlab.summercattle.addons.wechat.utils.SignUtils;
import com.gitlab.summercattle.commons.exception.CommonException;
import com.gitlab.summercattle.commons.utils.auxiliary.UuidUtils;
import com.gitlab.summercattle.commons.utils.reflect.ClassType;
import com.gitlab.summercattle.commons.utils.reflect.ReflectUtils;
import com.gitlab.summercattle.commons.utils.spring.RestTemplateUtils;

/**
 * 微信小程序服务实现
 * @author orange
 *
 */
@Service
public class MiniProgramServiceImpl implements MiniProgramService {

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

	@Autowired
	private MiniProgramConfigProperties miniProgramConfigProperties;

	@Autowired
	@Qualifier(WeChatConstants.REST_TEMPLATE_UTILS_NAME)
	private RestTemplateUtils restTemplateUtils;

	@Autowired
	private WeChatService weChatService;

	@Autowired
	private UserService userService;

	@Autowired(required = false)
	private UserPhoneNumberBindHandle userPhoneNumberBindHandle;

	@Autowired
	private UserBindStoreService userBindStoreService;

	@Autowired
	private SessionMemoryService sessionMemoryService;

	@Override
	public MiniProgramUserSession getSession(String source, String jsCode) throws CommonException {
		MiniProgramApplication miniProgramApplication = ApplicationUtils.getMiniProgramApplication(source, miniProgramConfigProperties);
		if (StringUtils.isBlank(jsCode)) {
			throw new CommonException("临时登录凭证为空");
		}
		String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + miniProgramApplication.getAppId() + "&secret="
				+ miniProgramApplication.getSecret() + "&js_code=" + jsCode + "&grant_type=authorization_code";
		logger.debug("微信小程序的会话请求地址:" + url);
		String strJson = restTemplateUtils.get(url, null, null, String.class);
		logger.debug("微信小程序的临时登录凭证:" + jsCode + ",返回:" + strJson);
		JSONObject respJson = JSON.parseObject(strJson);
		boolean isErrMsg = respJson.containsKey("errmsg");
		if (isErrMsg) {
			throw new CommonException("微信小程序登录接口异常,错误码:" + ((String) ReflectUtils.convertValue(ClassType.String, respJson.getIntValue("errcode")))
					+ ",错误信息:" + respJson.getString("errmsg"));
		}
		String openId = respJson.getString("openid");
		String unionId = respJson.getString("unionid");
		String sessionKey = respJson.getString("session_key");
		UserBindInfo userBindInfo = userBindStoreService.getUserBindInfo(source, AppType.MiniProgram, openId, unionId);
		String sessionId = UuidUtils.getUuid();
		long sessionTimeout = 0;
		MiniProgramUserSession session = null;
		if (userBindInfo != null) {
			session = new MiniProgramUserSession(sessionId, openId, unionId, sessionKey, userBindInfo.getId(), userBindInfo.getUserType(),
					userBindInfo.getInfo());
			sessionTimeout = miniProgramConfigProperties.getSessionTimeout();
		}
		else {
			session = new MiniProgramUserSession(sessionId, openId, unionId, sessionKey);
			sessionTimeout = miniProgramConfigProperties.getTemporarySessionTimeout();
		}
		sessionMemoryService.save(source, session, sessionTimeout);
		return session;
	}

	@Override
	public void bind(String source, String sessionId, String code, Map parameters) throws CommonException {
		AbstractUserSession session = userService.getSession(source, sessionId);
		if (AppType.MiniProgram != session.getType()) {
			throw new CommonException("应用类型'" + session.getType().toString() + "'不支持");
		}
		String accessToken = weChatService.getAccessToken(AppType.MiniProgram, source);
		if (StringUtils.isBlank(accessToken)) {
			throw new CommonException("微信小程序访问令牌为空");
		}
		if (StringUtils.isBlank(code)) {
			throw new CommonException("手机号获取凭证为空");
		}
		JSONObject requestJson = new JSONObject();
		requestJson.put("code", code);
		String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken;
		logger.debug("用于将code换取用户手机号接口,地址:" + url + ",请求Json:" + requestJson.toString());
		JSONObject resultJson = restTemplateUtils.post(url, MediaType.APPLICATION_JSON, null, requestJson, JSONObject.class);
		logger.debug("用于将code换取用户手机号接口,返回Json:" + resultJson.toString());
		int errcode = resultJson.getIntValue("errcode");
		if (errcode != 0) {
			throw new CommonException("用于将code换取用户手机号接口异常,错误码:" + resultJson.getIntValue("errcode") + ",错误信息:" + resultJson.getString("errmsg"));
		}
		String phoneNumber = resultJson.getJSONObject("phone_info").getString("phoneNumber");
		if (userPhoneNumberBindHandle == null) {
			throw new CommonException("用户手机号绑定处理为空");
		}
		BindUserInfo bindUserInfo = userPhoneNumberBindHandle.process(phoneNumber, parameters);
		if (bindUserInfo == null) {
			if (userPhoneNumberBindHandle.isAutoCreated(parameters)) {
				bindUserInfo = userPhoneNumberBindHandle.create(phoneNumber, parameters);
			}
			else {
				throw new CommonException("用户绑定失败");
			}
		}
		if (bindUserInfo == null) {
			throw new CommonException("绑定用户信息为空");
		}
		if (bindUserInfo.getUserType() == 0) {
			throw new CommonException("用户类型没有设置");
		}
		if (StringUtils.isBlank(bindUserInfo.getInfo())) {
			throw new CommonException("绑定信息为空");
		}
		String bindId = userBindStoreService.save(source, AppType.MiniProgram, session.getOpenId(), session.getUnionId(), bindUserInfo.getUserType(),
				bindUserInfo.getInfo());
		sessionMemoryService.invalid(source, sessionId);
		session.setBindUser(true);
		session.setBindId(bindId);
		session.setUserType(bindUserInfo.getUserType());
		session.setBindInfo(bindUserInfo.getInfo());
		int sessionTimeout = miniProgramConfigProperties.getSessionTimeout();
		sessionMemoryService.save(source, session, sessionTimeout);
	}

	@Override
	public List getUserEncryptKeys(String source, String sessionId) throws CommonException {
		AbstractUserSession session = userService.getSession(source, sessionId);
		if (AppType.MiniProgram != session.getType()) {
			throw new CommonException("应用类型'" + session.getType().toString() + "'不支持");
		}
		MiniProgramUserSession userSession = (MiniProgramUserSession) session;
		String accessToken = weChatService.getAccessToken(AppType.MiniProgram, source);
		if (StringUtils.isBlank(accessToken)) {
			throw new CommonException("微信小程序访问令牌为空");
		}
		String signature = SignUtils.signSha256Hmac(userSession.getSessionKey(), "");
		String url = "https://api.weixin.qq.com/wxa/business/getuserencryptkey?access_token=" + accessToken + "&openid=" + userSession.getOpenId()
				+ "&signature=" + signature + "" + "&sig_method=hmac_sha256";
		logger.debug("查询用户加密要素信息接口,地址:" + url);
		JSONObject resultJson = restTemplateUtils.post(url, MediaType.APPLICATION_JSON, null, null, JSONObject.class);
		logger.debug("查询用户加密要素信息接口,返回Json:" + resultJson.toString());
		int errcode = resultJson.getIntValue("errcode");
		if (errcode != 0) {
			throw new CommonException("查询用户加密要素信息接口异常,错误码:" + resultJson.getIntValue("errcode") + ",错误信息:" + resultJson.getString("errmsg"));
		}
		List userEncryptKeyInfos = new Vector();
		JSONArray keyInfoArray = resultJson.getJSONArray("key_info_list");
		for (int i = 0; i < keyInfoArray.size(); i++) {
			JSONObject keyInfoJson = keyInfoArray.getJSONObject(i);
			userEncryptKeyInfos.add(new UserEncryptKeyInfo(keyInfoJson.getString("encrypt_key"), keyInfoJson.getIntValue("version"),
					keyInfoJson.getIntValue("expire_in"), keyInfoJson.getString("iv"), new Date(keyInfoJson.getLongValue("create_time") * 1000L)));
		}
		return userEncryptKeyInfos;
	}

	@Override
	public boolean checkSessionKey(String source, String sessionId) throws CommonException {
		AbstractUserSession session = userService.getSession(source, sessionId);
		if (AppType.MiniProgram != session.getType()) {
			throw new CommonException("应用类型'" + session.getType().toString() + "'不支持");
		}
		MiniProgramUserSession userSession = (MiniProgramUserSession) session;
		String accessToken = weChatService.getAccessToken(AppType.MiniProgram, source);
		if (StringUtils.isBlank(accessToken)) {
			throw new CommonException("微信小程序访问令牌为空");
		}
		String signature = SignUtils.signSha256Hmac(userSession.getSessionKey(), "");
		String url = "https://api.weixin.qq.com/wxa/checksession?access_token=" + accessToken + "&signature=" + signature + "&openid="
				+ userSession.getOpenId() + "&sig_method=hmac_sha256";
		logger.debug("检查Session Key是否有效接口,地址:" + url);
		JSONObject resultJson = restTemplateUtils.get(url, MediaType.APPLICATION_JSON, null, JSONObject.class);
		logger.debug("检查Session Key是否有效接口,返回Json:" + resultJson.toString());
		int errcode = resultJson.getIntValue("errcode");
		return errcode == 0;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy