赞
踩
公司这两天开发微信小程序,记录一下微信登录的过程
1: 获取微信code、sessionKey(加密秘钥)、avatar(商家头像);
2: 通过微信code得到微信openID、微信unionID(微信唯一标识);
3: 通过微信unionID(微信唯一标识)查询数据库是否存在,存在则返回token给到前端,不存在则获取手机号(我这边的流程是小程序是和账号密码互通的);
4: 微信手机号授权通过前端传过来的微信openID、sessionKey(加密秘钥)、encryptedData(加密数据)、iv(加密算法初始向量)、avatar(商家头像)解析出手机号等信息,如果手机号存在则将微信unionID(这里的unionID可通过AccessToken和openId就可以获取到)修改到数据库中这样下次用户登录就会省去获取手机号的流程,如果手机号和微信unionID(微信唯一标识)均在数据库中都不存在则走注册流程。
注:部分 jdk1.9 需要引入 rt.jar
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.10</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.44</version> </dependency> <!-- 图片压缩 --> <dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>0.4.8</version> </dependency>
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.bouncycastle.util.encoders.Base64; import org.apache.http.util.TextUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.stereotype.Component; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.security.AlgorithmParameters; import java.security.Security; import java.util.*; /** * @ClassName WechatUtil * @Version 1.0 */ @Component public class WechatUtil { private static final String appId = "xxxxxxxxxxx"; private static final String secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; /** * 获取小程序codeid换取openid * * @param code * @return */ public static JSONObject getOpenId(String code) { String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"; PrintWriter out = null; BufferedReader in = null; String line; StringBuffer stringBuffer = new StringBuffer(); try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 //设置返回类型 conn.setRequestProperty("contentType", "text/plain"); //设置请求类型 conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(1000); conn.setReadTimeout(1000); conn.setDoOutput(true); conn.connect(); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 设置接收格式 in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); while ((line = in.readLine()) != null) { stringBuffer.append(line); } JSONObject jsonObject = JSONObject.parseObject(stringBuffer.toString()); return jsonObject; } catch (Exception e) { e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return null; } public static Map<String, Object> getPhoneNumber(LoginPhoneInfoParam vo) { Map<String,Object> map=new HashMap<>(); String openid= vo.getWechatOpenId(); String session_key = vo.getSessionKey(); if (!EmptyUtils.isEmpty(openid)) { if(EmptyUtils.isEmpty(session_key)){ return null; } map.put("openid",openid); // 被加密的数据 byte[] dataByte = Base64.decode(vo.getEncryptedData()); // 加密秘钥 byte[] keyByte = Base64.decode(session_key); // 偏移量 byte[] ivByte = Base64.decode(vo.getIv()); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16; String result = null; if (keyByte.length % base != 0) { int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0); byte[] temp = new byte[groups * base]; Arrays.fill(temp, (byte) 0); System.arraycopy(keyByte, 0, temp, 0, keyByte.length); keyByte = temp; } // 初始化 Security.addProvider(new BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); SecretKeySpec spec = new SecretKeySpec(keyByte, "AES"); AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES"); parameters.init(new IvParameterSpec(ivByte)); // 初始化 cipher.init(Cipher.DECRYPT_MODE, spec, parameters); byte[] resultByte = cipher.doFinal(dataByte); if (null != resultByte && resultByte.length > 0) { result = new String(resultByte, "UTF-8"); JSONObject jsonObject = JSONObject.parseObject(result); map.put("param",jsonObject); return map; } } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 获取小程序token * * @return */ public static String getAccessToken() { String url = "https://api.weixin.qq.com/cgi-bin/token?" + "appid=" + appId + "&secret=" + secret + "&grant_type=client_credential"; PrintWriter out = null; BufferedReader in = null; String line; StringBuffer stringBuffer = new StringBuffer(); try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 //设置返回类型 conn.setRequestProperty("contentType", "text/plain"); //设置请求类型 conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(1000); conn.setReadTimeout(1000); conn.setDoOutput(true); conn.connect(); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 设置接收格式 in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); while ((line = in.readLine()) != null) { stringBuffer.append(line); } JSONObject jsonObject = JSONObject.parseObject(stringBuffer.toString()); return jsonObject.getString("access_token"); } catch (Exception e) { e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return null; } /** * 获取小程序token和openid * * @param code * @return */ public static JSONObject getAccessTokenOrOpenid(String code) { String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code"; PrintWriter out = null; BufferedReader in = null; String line; StringBuffer stringBuffer = new StringBuffer(); try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 //设置返回类型 conn.setRequestProperty("contentType", "text/plain"); //设置请求类型 conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(1000); conn.setReadTimeout(1000); conn.setDoOutput(true); conn.connect(); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 设置接收格式 in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); while ((line = in.readLine()) != null) { stringBuffer.append(line); } JSONObject jsonObject = JSONObject.parseObject(stringBuffer.toString()); return jsonObject; } catch (Exception e) { e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return null; } /** * 获取小程序unionId * * @return */ public static String getUnionId(String accessToken,String openid) { String url = "https://api.weixin.qq.com/sns/userinfo?access_token="+accessToken+"&openid="+openid; PrintWriter out = null; BufferedReader in = null; String line; StringBuffer stringBuffer = new StringBuffer(); try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 设置请求格式 //设置返回类型 conn.setRequestProperty("contentType", "text/plain"); //设置请求类型 conn.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //设置超时时间 conn.setConnectTimeout(1000); conn.setReadTimeout(1000); conn.setDoOutput(true); conn.connect(); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 设置接收格式 in = new BufferedReader( new InputStreamReader(conn.getInputStream(), "UTF-8")); while ((line = in.readLine()) != null) { stringBuffer.append(line); } JSONObject jsonObject = JSONObject.parseObject(stringBuffer.toString()); return jsonObject.get("unionId").toString(); } catch (Exception e) { e.printStackTrace(); } //使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return null; } /** * 获取微信小程序 session_key 和 openid * * @param code 调用微信登陆返回的Code * @return */ public static JSONObject getSessionKeyOropenid(String code) { //微信端登录code值 String wxCode = code; String requestUrl = "https://api.weixin.qq.com/sns/jscode2session"; //请求地址 https://api.weixin.qq.com/sns/jscode2session Map<String, String> requestUrlParam = new HashMap<String, String>(); requestUrlParam.put("appid", appId); //开发者设置中的appId requestUrlParam.put("secret", secret); //开发者设置中的appSecret requestUrlParam.put("js_code", wxCode); //小程序调用wx.login返回的code requestUrlParam.put("grant_type", "authorization_code"); //默认参数 authorization_code //发送post请求读取调用微信 https://api.weixin.qq.com/sns/jscode2session 接口获取openid用户唯一标识 JSONObject jsonObject = JSON.parseObject(sendPost(requestUrl, requestUrlParam)); return jsonObject; } /** * 向指定 URL 发送POST方法的请求 * * @param url 发送请求的 URL * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, Map<String, ?> paramMap) { PrintWriter out = null; BufferedReader in = null; String result = ""; String param = ""; Iterator<String> it = paramMap.keySet().iterator(); while (it.hasNext()) { String key = it.next(); param += key + "=" + paramMap.get(key) + "&"; } try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Accept-Charset", "utf-8"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { log.error(e.getMessage(), e); } //使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } public static BufferedImage getWxacode(String accessToken, String path) { Map<String, String> paramMap = new HashMap<>(); paramMap.put("path", path); paramMap.put("width", "120"); String Json = JSONObject.toJSONString(paramMap); BufferedImage qrCodeImage = null; BufferedReader reader = null; try { URL url = new URL("https://api.weixin.qq.com/wxa/getwxacode?access_token=" + accessToken); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestProperty("Connection", "Keep-Alive"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); conn.setRequestProperty("accept", "*/*"); if (!TextUtils.isEmpty(Json)) { byte[] writebytes = Json.getBytes(); conn.setRequestProperty("Content-Length", String.valueOf(writebytes.length)); OutputStream outwritestream = conn.getOutputStream(); outwritestream.write(Json.getBytes()); outwritestream.flush(); outwritestream.close(); conn.getResponseCode(); } if (conn.getResponseCode() == 200) { qrCodeImage = ImageIO.read(conn.getInputStream()); } } catch (Exception e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return qrCodeImage; } }
import cn.hutool.core.codec.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.util.DigestUtils; import org.springframework.web.multipart.MultipartFile; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import java.net.HttpURLConnection; import java.net.URL; import java.security.Security; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @ClassName: EmptyUtils * @Description: 判空工具类 */ public class EmptyUtils { /** * @Title: isEmpty * @Description: 判断字符串是否为空,长度为0被认为是空字符串. * @param str * @return * @return Integer */ public static boolean isEmpty(String str) { if (null != str) { return str.trim().length() == 0; } else { return true; } } /** * @Title: isEmpty * @Description: 判断Bigdecimal类型是否为空或者0 * @return * @return Integer */ public static boolean isEmptyBigdecimal(BigDecimal decimal) { if(!EmptyUtils.isEmpty(decimal)){ if(decimal.compareTo(BigDecimal.ZERO)!=0){ return false; } } return true; } /** * @Title: isEmpty * @Description: 判断字符串是否为空,字符串前后空白被截断,截断后长度为0被认为是空字符串 * @param str * @param isTrimed 是否去掉前后空格 * @return * @return Integer */ public static boolean isEmpty(String str, boolean isTrimed) { if (isTrimed) { return null == str || str.trim().length() == 0; } else { return null == str || str.length() == 0; } } /** * @Title: isEmpty * @Description: 判断列表是否为空,列表没有元素也被认为是空 * @param collection * @return * @return Integer */ public static boolean isEmpty(Collection<?> collection) { return null == collection || collection.size() == 0; } public static boolean isNotEmpty(Collection<?> collection) { return !isEmpty(collection); } /** * @Title: isEmpty * @Description: 判断数组是否为空 * @param array * @return * @return Integer */ public static boolean isEmpty(Object[] array) { return null == array || array.length == 0; } /** * @Title: isEmpty * @Description: 判断对象是否为空 * @param obj * @return * @return Integer */ public static boolean isEmpty(Object obj) { return null == obj || "".equals(obj); } /** * @Title: isEmpty * @Description: 判断Long类型是否为空 * @param obj * @return * @return Integer */ public static boolean isLongEmpty(Long obj) { return null == obj || 0l.equals(obj); } /** * 截取字符串中的数字 * @param str * @return */ public static String checkNum(String str) { StringBuilder builder=new StringBuilder(); String regEx="(\\d+(\\.\\d+)?)"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(str); while (m.find()) {//当符合正则表达式定义的条件时 builder.append(m.group()); } return builder.toString(); } /** * 截取字符串中除了数字以外的字符串 * @param str * @return */ public static String checkNumOhter(String str) { StringBuilder builder=new StringBuilder(); String regEx="[^0-9.]"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(str); while (m.find()) {//当符合正则表达式定义的条件时 builder.append(m.group()); } return builder.toString(); } /** * 图片地址转MultipartFile */ public static MultipartFile downloadImageUrl(String imageUrl, Long id) { try { HttpURLConnection httpUrl = (HttpURLConnection) new URL(imageUrl).openConnection(); httpUrl.connect(); File file = inputStreamToFile(httpUrl.getInputStream(),"product-"+id+".png"); System.out.println("111====>>>>"+file.getPath()); }catch (Exception e){ e.printStackTrace(); } return null; } /** * 工具类 * inputStream 转 File */ public static File inputStreamToFile(InputStream ins, String name) throws Exception{ File file = new File("C:\\Users\\EDZ\\Pictures\\其他店铺3\\" + name); if (file.exists()) { return file; } OutputStream os = new FileOutputStream(file); int bytesRead; int len = 8192; byte[] buffer = new byte[len]; while ((bytesRead = ins.read(buffer, 0, len)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); ins.close(); ImageUtil.readImage(file); return file; } /** * 拿到字符串数组以逗号拼接成字符串返回 * @param images * @return */ public static String getImage(List<String> images) { String image=""; if(!EmptyUtils.isEmpty(images)){ for (int i = 0; i < images.size(); i++) { if(i==0||images.size()==1){ image=images.get(i); }else { image+=","+images.get(i); } } } return image; } /** * 拿到字符串数组以逗号拼接成字符串返回 * @param str * @return */ public static String getString(List<Long> str) { String image=""; if(!EmptyUtils.isEmpty(str)){ for (int i = 0; i < str.size(); i++) { if(i==0||str.size()==1){ image=String.valueOf(str.get(i)); }else { image+=","+str.get(i); } } } return image; } /** * 拿到字符串数组以分号拼接成字符串返回 * @param images * @return */ public static String getFenString(List<String> images) { String image=""; if(!EmptyUtils.isEmpty(images)){ for (int i = 0; i < images.size(); i++) { if(i==0||images.size()==1){ image=images.get(i); }else { image+=";"+images.get(i); } } } return image; } /** * 拿到对象数组获取地址以逗号拼接成字符串返回 * @param images * @return */ public static String getImageDateList(List<Image> images) { String image=""; if(!EmptyUtils.isEmpty(images)){ for (int i = 0; i < images.size(); i++) { String url = images.get(i).getImgPath(); if(i==0||images.size()==1){ image=url; }else { image+=","+url; } } } return image; } /** * 拿到图片数组封装成数组对象 */ public static List<Image> getImages(List<String> list){ if(!EmptyUtils.isEmpty(list)){ List<Image> collect = list.stream() .map(a -> { Image image = new Image(); image.setImgPath(a); return image; }).collect(Collectors.toList()); return collect; } return null; } /** * 拿到图片拼接字符串封装成数组对象(以逗号拼接) */ public static List<String> getImages(String image){ if(!EmptyUtils.isEmpty(image)){ String[] split = image.split(","); return Arrays.asList(split); } return null; } /** * 拿到图片拼接字符串封装成数组对象(以分号拼接) */ public static List<String> getFenStrings(String image){ if(!EmptyUtils.isEmpty(image)){ String[] split = image.split(";"); return Arrays.asList(split); } return null; } /** * * @param secretInfo 微信返回的req_info的值 * @param weChatKey 微信的key * @return * @throws Exception */ public static String decryption(String secretInfo, String weChatKey) throws Exception { try { //对商户key做md5,得到32位小写key* SecretKeySpec key = new SecretKeySpec(DigestUtils.md5DigestAsHex(getContentBytes(weChatKey, "utf-8")).toLowerCase().getBytes(), "AES"); //创建密码器 Security.addProvider(new BouncyCastleProvider()); //用key*对加密串B做AES-256-ECB解密(PKCS7Padding) Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC"); cipher.init(Cipher.DECRYPT_MODE, key); //返回解密后的内容 return new String(cipher.doFinal(Base64.decode(secretInfo))); } catch (Exception e) { e.printStackTrace(); } return null; } private static byte[] getContentBytes(String content, String charset) { if (charset == null || "".equals(charset)) { return content.getBytes(); } try { return content.getBytes(charset); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 计算切分次数 */ public static Integer countStep(Integer size, int input) { return (size + input - 1) / input; } /** * @param list 需要分隔的 集合 * @param input 指定分隔size * @return */ public static List<List<CereRedisKey>> split(List<CereRedisKey> list, int input) { int limit = countStep(list.size(), input); List<List<CereRedisKey>> splitList; splitList = Stream.iterate(0, n -> n + 1).limit(limit). map(a -> list.stream().skip(a * input).limit(input).collect(Collectors.toList())). collect(Collectors.toList()); //当输入数量小于分隔数量需反转 if (input<limit){ splitList = Stream.iterate(0, n -> n + 1).limit(input). map(a -> list.stream().skip(a * limit).limit(limit).collect(Collectors.toList())). collect(Collectors.toList()); } return splitList; } /** * 过滤表情包参数 * @param source * @return */ public static String filterEmoji(String source) { if(source != null) { Pattern emoji = Pattern.compile ("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",Pattern.UNICODE_CASE | Pattern . CASE_INSENSITIVE ) ; Matcher emojiMatcher = emoji.matcher(source); if ( emojiMatcher.find()) { source = emojiMatcher.replaceAll("*"); return source ; } return source; } return source; } }
import com.alibaba.fastjson.JSONObject; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.WxUserReturnInfo; import com.example.chinese_dance.model.UsUser; import com.example.chinese_dance.vo.EbUserVo; import com.example.chinese_dance.vo.UsUserVo; import com.example.chinese_dance.vo.WxUserVo; import java.util.List; import java.util.Map; /** * <p> * 用户账号 服务类 * </p> * * @author ys * @since 2022-03-05 */ public interface UsUserService { /** * 微信登录 * @param param * @return */ WxUserReturnInfo wxLogin(LoginPhoneInfoParam param); /** * 微信获取手机登录 * @param param * @return */ WxUserReturnInfo wxPhoneLogin(LoginPhoneInfoParam param); }
import com.example.chinese_dance.model.WxUser; import com.example.chinese_dance.param.login.WxUserReturnInfo; import org.apache.ibatis.annotations.Param; import java.util.List; /** * <p> * 微信小程序用户表 服务类 * </p> * * @author ys123 * @since 2022-07-08 */ public interface WxUserService { /** * WxUser 入库操作 */ boolean insert(WxUser arg) throws Exception; /** * WxUser 修改操作 */ boolean update(WxUser arg) throws Exception; /** * 通过wechatUnionId或手机号查询用户信息 * @param unionId * @return */ WxUserReturnInfo findByUnionIdAndPhone(@Param("wechatUnionId") String unionId,@Param("phone") String phone); }
import com.alibaba.cloud.commons.lang.StringUtils; import com.alibaba.fastjson.JSONObject; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.WxUserReturnInfo; import com.example.chinese_dance.util.DateTool; import com.example.chinese_dance.util.DesensitizationUtil; import com.example.chinese_dance.util.loginUtil.EmptyUtils; import com.example.chinese_dance.util.loginUtil.WechatUtil; import com.example.chinese_dance.vo.EbUserVo; import com.example.chinese_dance.vo.UsUserVo; import com.example.chinese_dance.vo.WxUserVo; import com.example.common.base.ApiReturnCodeEnum; import com.example.common.base.Params; import com.example.common.exception.ATException; import com.example.common.util.IdWorker; import com.example.common.util.MD5; import com.example.common.util.MyRestTemplate; import com.example.common.util.Tree.BuildTree; import com.example.common.util.Tree.BuildTreeUtils; import com.example.common.util.UserInfo; import com.example.chinese_dance.dao.UsUserDao; import com.example.chinese_dance.dao.mapper.UsUserMapper; import com.example.chinese_dance.model.*; import com.example.chinese_dance.service.*; import com.example.token.JwtUtils; import net.sf.json.JSONArray; import org.apache.commons.beanutils.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.util.*; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; /** * <p> * 用户账号 服务实现类 * </p> * * @author ys */ @Service public class UsUserServiceImpl implements UsUserService { @Autowired UsUserMapper objectMapper; @Autowired UsUserDao objectDao; @Autowired MyRestTemplate myRestTemplate; @Autowired UsUserService usUserService; @Autowired StringRedisTemplate stringRedisTemplate; @Autowired UserInfo userInfo; @Autowired UsPowerService usPowerService; @Autowired WxUserService wxUserService; @Autowired EbUserService ebUserService; Map<String, String> unionIdMap = new HashMap<>(); @Override @Transactional(readOnly = false,rollbackFor = Exception.class) public WxUserReturnInfo wxLogin(LoginPhoneInfoParam param) { WxUserReturnInfo user = null; boolean flag=false; try { // 根据微信code获取相关信息 JSONObject wx = WechatUtil.getOpenId(param.getCode()); String openid = wx.get("openid").toString(); String sessionkey = wx.get("session_key").toString(); String unionId = ""; if (!EmptyUtils.isEmpty(wx.get("unionid"))) { unionId = wx.get("unionid").toString(); WxUserReturnInfo byUnionid = wxUserService.findByUnionIdAndPhone(unionId,null); if (!ObjectUtils.isEmpty(byUnionid)) { WxUser wxUser=new WxUser(); wxUser.setId(byUnionid.getId()); wxUser.setWechatOpenId(openid); wxUser.setUpdateTime(new Date()); wxUser.setAvatar(param.getAvatar()); //查询另外一个系统是否有对应的手机号 List<EbUser> ebUserList = ebUserService.query(byUnionid.getPhone(), null); if(!ObjectUtils.isEmpty(ebUserList)){ if(ebUserList.size()==1){ EbUser ebUser=ebUserList.get(0); //关联另一个系统的用户表 wxUser.setEbUserId(ebUser.getUid()); } }else{ //没有在另外一个系统中查出来手机号则在eb_user表中新增一个用户 EbUser ebUser=new EbUser(); Integer nowTimeInt=DateTool.dateByInt(); ebUser.setAccount("wx"+ nowTimeInt); //默认密码:123456 ebUser.setPwd(MD5.encoder("123456")); ebUser.setAvatar(param.getAvatar()); ebUser.setPhone(byUnionid.getPhone()); ebUser.setAddTime(nowTimeInt); if(StringUtils.isNotBlank(param.getIp())) { ebUser.setAddIp(param.getIp()); ebUser.setLastIp(param.getIp()); } ebUser.setLastTime(nowTimeInt); ebUser.setStatus(false); flag=ebUserService.insert(ebUser); if(!flag){ throw new ATException("用户信息入库失败~",ApiReturnCodeEnum.customTips); } } flag=wxUserService.update(wxUser); if(!flag){ throw new ATException("用户信息更新失败~",ApiReturnCodeEnum.customTips); } user=new WxUserReturnInfo(); BeanUtils.copyProperties(user,wxUser); user.setUserId(byUnionid.getId()); String token =JwtUtils.generateToken(byUnionid.getId()); user.setToken(token); user.setPhone(byUnionid.getPhone()); //存token stringRedisTemplate.opsForValue().set(Params.key + token,user.toString()); stringRedisTemplate.expire(Params.key + token, Params.token_timeout, TimeUnit.SECONDS); user.setIsFlagPhone(false); } else { user = new WxUserReturnInfo(); user.setWechatOpenId(openid); user.setSessionKey(sessionkey); unionIdMap.put(openid, unionId); user.setIsFlagPhone(true); user.setAvatar(param.getAvatar()); } } else { throw new ATException("unionid解析失败~", ApiReturnCodeEnum.customTips); } } catch (Exception e) { e.printStackTrace(); } return user; } @Override @Transactional(readOnly = false,rollbackFor = Exception.class) public WxUserReturnInfo wxPhoneLogin(LoginPhoneInfoParam param) { WxUserReturnInfo wxUserReturnInfo = new WxUserReturnInfo(); boolean flag=false; String token=null; try { WxUser result = new WxUser(); Map<String, Object> map = WechatUtil.getPhoneNumber(param); if (EmptyUtils.isEmpty(map)) { throw new ATException("解析手机号失败~", ApiReturnCodeEnum.customTips); } String phone = ""; Object phoneNumber = map.get("param"); String jsonString = JSONObject.toJSONString(phoneNumber); JSONObject obj = JSONObject.parseObject(jsonString); if (!EmptyUtils.isEmpty(jsonString)) { phone = obj.get("phoneNumber").toString(); } String unionId = unionIdMap.get(param.getWechatOpenId()); //校验手机号是否能查询到相关的用户 WxUserReturnInfo allByPhone = wxUserService.findByUnionIdAndPhone(null, phone); if (!ObjectUtils.isEmpty(allByPhone)) { result.setId(allByPhone.getId()); result.setWechatOpenId(param.getWechatOpenId()); result.setWechatUnionId(unionId); result.setAvatar(param.getAvatar()); result.setUpdateTime(new Date()); //查询另外一个系统是否有对应的手机号 List<EbUser> ebUserList = ebUserService.query(phone, null); if(!ObjectUtils.isEmpty(ebUserList)){ if(ebUserList.size()==1){ EbUser ebUser=ebUserList.get(0); //关联另一个系统的用户表 result.setEbUserId(ebUser.getUid()); } }else{ //没有在另外一个系统中查出来手机号则在eb_user表中新增一个用户 EbUser ebUser=new EbUser(); Integer nowTimeInt=DateTool.dateByInt(); ebUser.setAccount("wx"+ nowTimeInt); //默认密码:123456 ebUser.setPwd(MD5.encoder("123456")); ebUser.setAvatar(param.getAvatar()); ebUser.setPhone(phone); ebUser.setAddTime(nowTimeInt); if(StringUtils.isNotBlank(param.getIp())) { ebUser.setAddIp(param.getIp()); ebUser.setLastIp(param.getIp()); } ebUser.setLastTime(nowTimeInt); ebUser.setStatus(false); flag=ebUserService.insert(ebUser); if(!flag){ throw new ATException("用户信息入库失败~",ApiReturnCodeEnum.customTips); } } flag=wxUserService.update(result); if(!flag){ throw new ATException("用户信息更新失败~",ApiReturnCodeEnum.customTips); } token = JwtUtils.generateToken(allByPhone.getId()); BeanUtils.copyProperties(wxUserReturnInfo, result); wxUserReturnInfo.setUserId(allByPhone.getId()); wxUserReturnInfo.setToken(token); wxUserReturnInfo.setWechatUnionId(""); unionIdMap.remove(param.getWechatOpenId()); wxUserReturnInfo.setPhone(phone); wxUserReturnInfo.setWechatName(allByPhone.getWechatName()); wxUserReturnInfo.setBrief(allByPhone.getBrief()); } else { //注册 String userId=IdWorker.generSequeId(); result.setId(userId); token = JwtUtils.generateToken(userId); //手机号脱敏作为用户名 result.setWechatName(DesensitizationUtil.mobileEncrypt(phone)); result.setBrief("暂无简介"); result.setWechatOpenId(param.getWechatOpenId()); result.setWechatUnionId(unionId); result.setAvatar(param.getAvatar()); result.setPhone(phone); //查询另外一个系统是否有对应的手机号 List<EbUser> ebUserList = ebUserService.query(phone, null); if(!ObjectUtils.isEmpty(ebUserList)){ if(ebUserList.size()==1){ EbUser ebUser=ebUserList.get(0); //关联另一个系统的用户表 result.setEbUserId(ebUser.getUid()); } } unionIdMap.remove(param.getWechatOpenId()); flag=wxUserService.insert(result); if(!flag){ throw new ATException("新用户注册失败~",ApiReturnCodeEnum.customTips); } BeanUtils.copyProperties(wxUserReturnInfo, result); wxUserReturnInfo.setUserId(userId); } //存token stringRedisTemplate.opsForValue().set(Params.key + token, wxUserReturnInfo.toString()); stringRedisTemplate.expire(Params.key + token, Params.token_timeout, TimeUnit.SECONDS); }catch (Exception e){ e.printStackTrace(); } return wxUserReturnInfo; } }
import com.example.chinese_dance.param.login.WxUserReturnInfo; import com.example.common.util.IdWorker; import com.example.chinese_dance.dao.WxUserDao; import com.example.chinese_dance.dao.mapper.WxUserMapper; import com.example.chinese_dance.model.WxUser; import com.example.chinese_dance.model.WxUserExample; import com.example.chinese_dance.service.WxUserService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.List; /** * <p> * 微信小程序用户表 服务实现类 * </p> * * @author ys123 * @since 2022-07-08 */ @Service public class WxUserServiceImpl implements WxUserService { @Autowired WxUserMapper objectMapper; @Autowired WxUserDao objectDao; @Override public boolean insert(WxUser object) throws Exception { if (StringUtils.isBlank(object.getId())) { String id = IdWorker.generSequeId(); object.setId(id); } object.setCreateTime(new Date()); object.setDel(Short.valueOf("0")); int count = objectMapper.insertSelective(object); if (count > 0) return true; return false; } @Override public boolean update(WxUser object) throws Exception { object.setUpdateTime(new Date()); int count = objectMapper.updateByPrimaryKeySelective(object); if (count > 0) return true; return false; } @Override public WxUserReturnInfo findByUnionIdAndPhone(String unionId,String phone) { return objectDao.findByUnionId(unionId,phone); } }
import com.alibaba.fastjson.JSONObject; import com.example.chinese_dance.param.backstageLogin.BackstageLoginParam; import com.example.chinese_dance.param.login.LoginParam; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.LoginPhoneInfoParam; import com.example.chinese_dance.param.login.WxUserReturnInfo; import com.example.chinese_dance.service.UsUserService; import com.example.chinese_dance.util.loginUtil.WechatUtil; import com.example.common.base.ApiReturnCodeEnum; import com.example.common.base.RestResponse; import com.example.common.util.MyRestTemplate; import com.github.pagehelper.util.StringUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestClientException; import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping("/open/auth") @Api(tags = {"认证接口,通用固定,认证后返回的\\'token\\'等同于\\'Authorization\\ v1.0"}) public class AuthController { private final static Logger logger = LoggerFactory.getLogger(AuthController.class); @Value("${server.port}") String port; @Autowired MyRestTemplate myRestTemplate; @Autowired UsUserService usUserService; /** * 微信授权登录 * * @param param 封装json对象 * @return */ @PostMapping("wxLogin") @ApiOperation(value = "微信授权登录") public RestResponse<LoginParam> wxLogin(@RequestBody LoginPhoneInfoParam param) { WxUserReturnInfo personal = usUserService.wxLogin(param); return RestResponse.success(personal); } @PostMapping("wxPhoneLogin") @ApiOperation(value = "微信获取手机登录") public RestResponse<LoginParam> wxPhoneLogin(@RequestBody LoginPhoneInfoParam param, HttpServletRequest request){ WxUserReturnInfo personal = usUserService.wxPhoneLogin(param); request.getAttribute("openid"); return RestResponse.success(personal); } /** * 获取微信加密秘钥 * @param param 封装json对象 * @return */ @PostMapping("getSessionKey") @ApiOperation(value = "获取微信加密秘钥") public RestResponse<WxUserReturnInfo> getSessionKey(@RequestBody LoginParam param){ //传入code后然后获取openid和session_key的,把他们封装到json里面 JSONObject json = WechatUtil.getSessionKeyOropenid(param.getCode()); String session_key = json.getString("session_key"); String openid = json.get("openid").toString(); WxUserReturnInfo platformBusinessReturnInfo=new WxUserReturnInfo(); platformBusinessReturnInfo.setSessionKey(session_key); platformBusinessReturnInfo.setWechatOpenId(openid); return RestResponse.success(platformBusinessReturnInfo); } }
UserReturnInfo 手机号授权(返回值)
import com.shop.cereshop.commons.domain.business.CerePlatformBusiness; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 登录返回参数 */ @Data @ApiModel(value = "PlatformBusinessReturnInfo", description = "登录返回参数") public class PlatformBusinessReturnInfo extends CerePlatformBusiness { /** * 微信code */ @ApiModelProperty(value = "微信code") private String code; /** * 商家用户id */ @ApiModelProperty(value = "商家用户id") private Long businessUserId; /** * 店铺Id */ @ApiModelProperty(value = "店铺Id") private Long shopId; /** * 商家登录账号 */ @ApiModelProperty(value = "商家登录账号") private String username; /** * 微信昵称 */ @ApiModelProperty(value = "微信昵称") private String wechatName; /** * 微信openid */ @ApiModelProperty(value = "微信openid") private String wechatOpenId; /** * 微信unionId */ @ApiModelProperty(value = "微信unionId") private String wechatUnionId; /** * 绑定手机号 */ @ApiModelProperty(value = "绑定手机号") private String phone; /** * 请求token */ @ApiModelProperty(value = "请求token") private String token; /** * 是否启用状态 1-是 0-否 */ @ApiModelProperty(value = "是否启用状态 1-是 0-否") private Integer state; /** * 商家头像 */ @ApiModelProperty(value = "商家头像") private String avatar; /** * 微信加密秘钥 */ @ApiModelProperty(value = "微信加密秘钥") private String sessionKey; /** * 加密数据 */ @ApiModelProperty(value = "加密数据") private String encryptedData; /** * 加密算法初始向量 */ @ApiModelProperty(value = "加密算法初始向量") private String iv; /** * 是否获取手机号 */ @ApiModelProperty(value = "是否获取手机号") private Boolean isFlagPhone; }
CerePlatformBusiness手机号授权(参数)
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; /** * cere_platform_business 平台商家用户实体类 * @author */ @Data @ApiModel(value = "CerePlatformBusiness", description = "平台商家用户实体类") public class CerePlatformBusiness implements Serializable { /** * 店铺id */ private Long shopId; /** * 商家用户id */ @ApiModelProperty(value = "商家用户id") @TableId(type = IdType.AUTO) private Long businessUserId; /** * 商家登录账号 */ @ApiModelProperty(value = "商家登录账号") private String username; /** * 商家登录密码 */ @ApiModelProperty(value = "商家登录密码") @JsonIgnore private String password; /** * 商家昵称 */ @ApiModelProperty(value = "商家昵称") private String name; /** * 商家头像 */ @ApiModelProperty(value = "商家头像") private String avatar; /** * 手机号 */ @ApiModelProperty(value = "手机号") private String phone; /** * 商家性别 */ @ApiModelProperty(value = "商家性别") private String sex; /** * 商家邮箱 */ @ApiModelProperty(value = "商家邮箱") private String email; /** * 用户token */ @ApiModelProperty(value = "用户token 停用") private String token; /** * 是否启用 1-是 0-否 */ @ApiModelProperty(value = "是否启用 1-是 0-否") private Integer state; /** * 创建时间 */ @ApiModelProperty(value = "创建时间") private String createTime; /** * 更新时间 */ @ApiModelProperty(value = "更新时间") private String updateTime; /** * 微信openID */ @ApiModelProperty(value = "微信openID") private String wechatOpenId; /** * 微信unionId */ @ApiModelProperty(value = "微信unionId") private String wechatUnionId; /** * 微信昵称 */ @ApiModelProperty(value = "微信昵称") private String wechatName; /** * 微信号 */ @ApiModelProperty(value = "微信号") private String wechatNumber; private static final long serialVersionUID = 1L; }
LoginParam登录请求参数(返回值)
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 登录请求参数 */ @Data @ApiModel(value = "LoginParam", description = "登录请求参数") public class LoginParam { /** * 微信code */ @ApiModelProperty(value = "微信code") private String code; /** * 商家登录账号 */ @ApiModelProperty(value = "商家登录账号") private String username; /** * 微信昵称 */ @ApiModelProperty(value = "微信昵称") private String wechatName; /** * 微信openid */ @ApiModelProperty(value = "微信openid") private String wechatOpenId; /** * 微信unionId */ @ApiModelProperty(value = "微信unionId") private String wechatUnionId; /** * 绑定手机号 */ @ApiModelProperty(value = "绑定手机号") private String phone; /** * 请求token */ @ApiModelProperty(value = "请求token") private String token; /** * 是否启用状态 1-是 0-否 */ @ApiModelProperty(value = "是否启用状态 1-是 0-否") private Integer state; /** * 商家头像 */ @ApiModelProperty(value = "商家头像") private String avatar; /** * 加密数据 */ @ApiModelProperty(value = "加密数据") private String encryptedData; /** * 加密算法初始向量 */ @ApiModelProperty(value = "加密算法初始向量") private String iv; }
LoginPhoneInfoParam手机号授权(参数)
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 手机号授权 */ @Data @ApiModel(value = "LoginPhoneInfoParam", description = "手机号授权") public class LoginPhoneInfoParam { /** * 微信code */ @ApiModelProperty(value = "微信code") private String code; /** * 微信openID */ @ApiModelProperty(value = "微信openID") private String wechatOpenId; /** * 微信unionID */ @ApiModelProperty(value = "微信unionID") private String wechatUnionId; /** * 加密秘钥 */ @ApiModelProperty(value = "加密秘钥") private String sessionKey; /** * 加密数据 */ @ApiModelProperty(value = "加密数据") private String encryptedData; /** * 加密算法初始向量 */ @ApiModelProperty(value = "加密算法初始向量") private String iv; /** * 商家头像 */ @ApiModelProperty(value = "商家头像") private String avatar; }
LoginPhoneInfoParam手机号授权
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 手机号授权 */ @Data @ApiModel(value = "LoginPhoneInfoParam", description = "手机号授权") public class LoginPhoneInfoParam{ /** * 微信openID */ @ApiModelProperty(value = "微信openID") private String wechatOpenId; /** * 加密秘钥 */ @ApiModelProperty(value = "加密秘钥") private String sessionKey; /** * 加密数据 */ @ApiModelProperty(value = "加密数据") private String encryptedData; /** * 加密算法初始向量 */ @ApiModelProperty(value = "加密算法初始向量") private String iv; /** * 头像 */ @ApiModelProperty(value = "头像") private String avatar; /** * ip */ @ApiModelProperty(value = "ip") private String ip; }
LoginParam登录返回参数
import com.example.chinese_dance.vo.UsUserVo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 登录返回参数 */ @Data @ApiModel(value = "LoginParam", description = "登录返回参数") public class WxUserReturnInfo extends UsUserVo { /** * 微信code */ @ApiModelProperty(value = "微信code") private String code; /** * 用户id */ @ApiModelProperty(value = "用户id") private String userId; /** * 微信昵称 */ @ApiModelProperty(value = "微信昵称") private String wechatName; /** * 微信openid */ @ApiModelProperty(value = "微信openid") private String wechatOpenId; /** * 微信unionId */ @ApiModelProperty(value = "微信unionId") private String wechatUnionId; /** * 绑定手机号 */ @ApiModelProperty(value = "绑定手机号") private String phone; /** * 请求token */ @ApiModelProperty(value = "请求token") private String token; /** * 是否启用状态 0-是 1-否 */ @ApiModelProperty(value = "是否启用状态 0-是 1-否") private Integer del; /** * 头像 */ @ApiModelProperty(value = "头像") private String avatar; /** * 微信加密秘钥 */ @ApiModelProperty(value = "微信加密秘钥") private String sessionKey; /** * 加密数据 */ @ApiModelProperty(value = "加密数据") private String encryptedData; /** * 加密算法初始向量 */ @ApiModelProperty(value = "加密算法初始向量") private String iv; /** * 是否获取手机号 */ @ApiModelProperty(value = "是否获取手机号") private Boolean isFlagPhone; @ApiModelProperty(value = "简介") private String brief; }
PageParam分页参数
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "PageParam", description = "分页参数")
public class PageParam {
@ApiModelProperty(value = "页码")
private Integer pageNo;
@ApiModelProperty(value = "页数")
private Integer pageSize;
}
如果没有在微信开放平台绑定微信小程序的话通过code是没有办法获取到微信用户的unionId的。
小程序登录需要先注册一个微信小程序,进行登录流程前必须要获取小程序的小程序appid、小程序秘钥secret
这里好像漏了几个工具类和参数类,如果看到需要的话可以留言我这边有时间补上
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。