package com.ltkj.web.controller.app; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.ltkj.common.core.controller.BaseController; import com.ltkj.common.core.domain.AjaxResult; import com.ltkj.common.utils.StringUtils; import com.ltkj.common.utils.WechatUtil; import com.ltkj.common.utils.sign.Base64; import com.ltkj.framework.config.JwtUtils; import com.ltkj.framework.config.UserHoder; import com.ltkj.hosp.domain.GetPhone; import com.ltkj.hosp.domain.Wxuser; import com.ltkj.hosp.service.IAbucoderWxuserService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.aspectj.bridge.MessageWriter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import sun.misc.BASE64Decoder; import javax.annotation.Resource; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.*; import java.io.*; import java.net.URL; import java.security.AlgorithmParameters; import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * @Author: 西安路泰科技有限公司/赵佳豪 * @Date: 2022/11/17 11:01 */ /** * 客户移动端端操作接口 */ @RestController @RequestMapping("/cus") @Api(tags = "A小程序端登录接口大全") @Slf4j public class WxloginController extends BaseController { @Resource private IAbucoderWxuserService wxuserService; @Value("${xcx.appid}") private String appid; @Value("${xcx.secret}") private String secret; /** * 小程序登录 * @param code 小程序wx.login返回的临时凭证 * @return */ @PostMapping("/wx/login") @ApiOperation("小程序登录接口") public AjaxResult login(@RequestParam @ApiParam(value = "code") String code, @RequestParam @ApiParam(value = "number") String number, @RequestParam @ApiParam(value = "iv") String iv) { // 用户登录凭证(有效期五分钟) if (StringUtils.isEmpty(code)) { return AjaxResult.error("登录凭证不能为空"); } JSONObject jsonObject = code2sessionKey(code); String openId = jsonObject.getString("openid"); String sessionKey = jsonObject.getString("session_key"); if (StringUtils.isEmpty(openId)) { return AjaxResult.error("登录失败,无效的登录凭证"); } JSONObject parse = decryptionUserInfo(number, sessionKey, iv); if (null != parse) { LambdaQueryWrapper wq = new LambdaQueryWrapper<>(); wq.eq(Wxuser::getOpenid, openId); Wxuser one = wxuserService.getOne(wq); Map map = new HashMap<>(); if (null != one) { one.setUpdateTime(new Date()); one.setWxMiniOpenId(openId); wxuserService.updateById(one); map.put("wxuser", one); } else { Wxuser wxuser = new Wxuser(); wxuser.setOpenid(openId); wxuser.setNickname(parse.get("nickName").toString()); wxuser.setAvatar(parse.get("avatarUrl").toString()); wxuser.setGender((Integer) parse.get("gender")); wxuser.setCreateTime(new Date()); wxuser.setWxMiniOpenId(openId); wxuserService.save(wxuser); map.put("wxuser",wxuser); } // 生成令牌 String token = JwtUtils.getToken(map); Map map1 = new HashMap<>(); map1.put("token", token); map1.put("openId", openId); map1.put("sessionKey", sessionKey); return AjaxResult.success(map1); } return AjaxResult.success("授权失败"); } /** * @return */ @GetMapping("/wx/getWxInfo") @ApiOperation(value = "小程序获取用户详情信息接口") public AjaxResult getWxInfo() { Wxuser wxuser = UserHoder.getWxuser(); LambdaQueryWrapperwq=new LambdaQueryWrapper<>(); wq.eq(Wxuser::getOpenid,wxuser.getOpenid()); Wxuser one = wxuserService.getOne(wq); return AjaxResult.success(one); } /** * 微信手机号码绑定 */ @PostMapping("/wx/bindPhone") @ApiOperation(value = "根据身份证号获取用户信息") public AjaxResult bindPhone(@RequestParam String openId, @RequestParam String sessionKey, @RequestParam String iv, @RequestParam String encryptedData, @RequestParam String code) { LambdaQueryWrapper wq = new LambdaQueryWrapper<>(); wq.eq(Wxuser::getOpenid, openId); Wxuser one = wxuserService.getOne(wq); if (one != null) { try { BASE64Decoder decoder = new BASE64Decoder(); byte[] raw = decoder.decodeBuffer(sessionKey); SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); IvParameterSpec iv1 = new IvParameterSpec(decoder.decodeBuffer(iv)); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv1); OkHttpClient client = new OkHttpClient(); Request okrequest = new Request.Builder() .url("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret) .build(); Response okresponse = client.newCall(okrequest).execute(); String responsedata = okresponse.body().string(); Gson gson = new Gson(); GetPhone o = gson.fromJson(responsedata, new TypeToken() { }.getType()); com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject(); jsonObject.put("code", code); String json = jsonObject.toString(); String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + o.getAccess_token(); RestTemplate restTemplate = new RestTemplate(); String result = restTemplate.postForObject(url, json, String.class); String getJsona = com.alibaba.fastjson2.JSON.parseObject(result).getString("phone_info"); String strjsona = com.alibaba.fastjson2.JSON.parseObject(getJsona, String.class); //指定获取 字段名对象信息,如果为单个String可不指定,这里作为实例写出 String phone = com.alibaba.fastjson2.JSON.parseObject(strjsona).getString("phoneNumber"); one.setPhone(phone); one.setUpdateTime(new Date()); if (wxuserService.updateById(one)) { return AjaxResult.success(phone); } return AjaxResult.success(phone); } catch (Exception ex) { return AjaxResult.success(); } } return AjaxResult.success(); } /** * 发送请求用code换取sessionKey和相关信息 * @param code * @return */ public JSONObject code2sessionKey(String code) { String stringToken = String.format( "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appid, secret, code); String response = httpsRequestToString(stringToken, "GET", null); return JSON.parseObject(response); } /** * 小程序解密用户数据 * @param encryptedData * @param sessionKey * @param iv * @return */ public static JSONObject decryptionUserInfo(String encryptedData, String sessionKey, String iv) { // 被加密的数据 byte[] dataByte = Base64.decode(encryptedData); // 加密秘钥 byte[] keyByte = Base64.decode(sessionKey); // 偏移量 byte[] ivByte = Base64.decode(iv); try { // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 int base = 16; 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) { String result = new String(resultByte, "UTF-8"); return JSONObject.parseObject(result); } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 发送https请求 * * @param path * @param method * @param body * @return */ public String httpsRequestToString(String path, String method, String body) { if (path == null || method == null) { return null; } String response = null; InputStream inputStream = null; InputStreamReader inputStreamReader = null; BufferedReader bufferedReader = null; HttpsURLConnection conn = null; try { // 创建SSLConrext对象,并使用我们指定的信任管理器初始化 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); TrustManager[] tm = {new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }}; sslContext.init(null, tm, new java.security.SecureRandom()); // 从上面对象中得到SSLSocketFactory SSLSocketFactory ssf = sslContext.getSocketFactory(); URL url = new URL(path); conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ssf); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); // 设置请求方式(get|post) conn.setRequestMethod(method); // 有数据提交时 if (null != body) { OutputStream outputStream = conn.getOutputStream(); outputStream.write(body.getBytes("UTF-8")); outputStream.close(); } // 将返回的输入流转换成字符串 inputStream = conn.getInputStream(); inputStreamReader = new InputStreamReader(inputStream, "UTF-8"); bufferedReader = new BufferedReader(inputStreamReader); String str = null; StringBuffer buffer = new StringBuffer(); while ((str = bufferedReader.readLine()) != null) { buffer.append(str); } response = buffer.toString(); } catch (Exception e) { } finally { if (conn != null) { conn.disconnect(); } try { bufferedReader.close(); inputStreamReader.close(); inputStream.close(); } catch (IOException execption) { } } return response; } }