diff --git a/jnpf-java-boot/jnpf-admin/src/main/resources/application.yml b/jnpf-java-boot/jnpf-admin/src/main/resources/application.yml index 674a441..1fc0f6a 100644 --- a/jnpf-java-boot/jnpf-admin/src/main/resources/application.yml +++ b/jnpf-java-boot/jnpf-admin/src/main/resources/application.yml @@ -110,7 +110,7 @@ gateway: #- /api/permission/Users/* # 入站IP(禁止配置以外的IP访问block-url配置的接口) white-ip: - #- 192.168.0.10 + 192.168.0.66 #- 192.168.0.20 # 日志配置 diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-controller/src/main/java/jnpf/controller/WxController.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-controller/src/main/java/jnpf/controller/WxController.java index 1435ffa..5bdec93 100644 --- a/jnpf-java-boot/jnpf-scm/jnpf-scm-controller/src/main/java/jnpf/controller/WxController.java +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-controller/src/main/java/jnpf/controller/WxController.java @@ -1,23 +1,38 @@ package jnpf.controller; +import cn.dev33.satoken.stp.SaTokenInfo; +import cn.dev33.satoken.stp.StpUtil; import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jnpf.base.ActionResult; +import jnpf.base.UserInfo; +import jnpf.entity.RecycleStationStaffEntity; +import jnpf.exception.LoginException; +import jnpf.model.LoginVO; +import jnpf.model.wx.AuthUserDto; +import jnpf.model.wx.WeChatUtil; import jnpf.model.wx.WxCheckSession; -import jnpf.model.wx.WxLoginParam; +import jnpf.service.AuthService; +import jnpf.service.RecycleStationStaffService; import jnpf.util.wxutil.HttpUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import javax.servlet.http.HttpServletRequest; import java.security.AlgorithmParameters; import java.security.Key; import java.security.Security; import java.util.Base64; +import java.util.HashMap; +import java.util.Map; @Slf4j @RestController @@ -33,6 +48,10 @@ public class WxController { private String code2Session; @Value("${wx.checkSession}") private String checkSession; + @Autowired + private RecycleStationStaffService recycleStationStaffService; + @Autowired + private AuthService authService; @Operation(summary = "小程序登录-回收员端") @GetMapping("/hsyLogin") @@ -43,6 +62,82 @@ public class WxController { } @Operation(summary = "小程序获取绑定的手机号-回收员端") + @PostMapping(value = "/hsyGetPhone") + public ActionResult login(@RequestBody AuthUserDto authUserDto, HttpServletRequest request) { + //String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + appsecret + "&js_code=" + authUserDto.getCode() + "&grant_type=authorization_code"; + String url = code2Session+"?appid="+appid+"&secret="+appsecret+"&js_code="+authUserDto.getCode()+"&grant_type=authorization_code"; + String loginResult = HttpUtil.sendHttpGet(url); + JSONObject loginResultObject = JSONObject.parseObject(loginResult); + // 登录失败 + /*if(null != loginResultObject.get("errcode")){ + return loginResult; + }*/ + // 登录成功 + //String sessionKey = (String) loginResultObject.get("session_key"); + + + /*String str = WeChatUtil.httpRequest(url, "GET", null); + JSONObject jsonObject = JSONObject.parseObject(str); + //wxMiniApi.authCode2Session(appId, secret, authUserDto.getCode()); + if (jsonObject == null) { + throw new RuntimeException("调用微信端授权认证接口错误"); + }*/ + String openId = (String) loginResultObject.get("openid"); + String sessionKey = (String) loginResultObject.get("session_key"); + String unionId = (String) loginResultObject.get("union_id"); + if (StringUtils.isEmpty(openId)) { + return ActionResult.fail(loginResultObject.getInteger("errcode"), loginResultObject.getString("errmsg")); + } + authUserDto.setOpenId(openId); + + //判断用户表中是否存在该用户,不存在则进行解密得到用户信息,并进行新增用户 + QueryWrapper queryWrapper=new QueryWrapper<>(); + queryWrapper.lambda().eq(RecycleStationStaffEntity::getOpenid,openId); + RecycleStationStaffEntity recycleStationStaffEntity = recycleStationStaffService.getOne(queryWrapper); + UserInfo userInfo2 = new UserInfo(); + if(recycleStationStaffEntity == null){ + String userInfo = WeChatUtil.decryptData(authUserDto.getEncryptedData(), sessionKey, authUserDto.getIv()); + if (StringUtils.isEmpty(userInfo)) { + throw new RuntimeException("解密用户信息错误"); + } + JSONObject userObject = JSONObject.parseObject(userInfo); + String phoneNumber = (String) userObject.get("phoneNumber"); + userInfo2.setUserAccount(phoneNumber); + RecycleStationStaffEntity user = new RecycleStationStaffEntity(); + user.setMobilePhone(phoneNumber); + user.setStaffsName(phoneNumber); + user.setOpenid(openId); + //user.setUnionId(unionId); + recycleStationStaffService.create(user); + authUserDto.setUserInfo(user); + } else { + authUserDto.setUserInfo(recycleStationStaffEntity); + } + Map map = new HashMap<>(); + map.put("account", "admin"); + map.put("password", "e10adc3949ba59abbe56e057f20f883e"); + map.put("grant_type", "password"); + String token = ""; + try { + ActionResult loginVOActionResult = authService.login(map); + token = loginVOActionResult.getData().getToken(); + } catch (LoginException e) { + throw new RuntimeException(e); + } + //创建token + //StpUtil.login("349057407209541"); + SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); + //String token = StpUtil.login(); + //userInfo.setToken(StpUtil.getTokenValueNotCut()); + if (StringUtils.isEmpty(token)) { + throw new RuntimeException("生成token错误"); + } + authUserDto.setToken(token); + return ActionResult.success(authUserDto); + } + + + /*@Operation(summary = "小程序获取绑定的手机号-回收员端") @PostMapping("/hsyGetPhone") public String hsyGetPhone(@RequestBody WxLoginParam wxLoginParam) { // todo @@ -60,7 +155,7 @@ public class WxController { JSONObject decrypt = decrypt(sessionKey,wxLoginParam.getEncryptedData(), wxLoginParam.getIv()); decrypt.put("sessionKey",sessionKey); return decrypt.toString(); - } + }*/ @Operation(summary = "小程序登录态校验-回收员端") @GetMapping("/hsyCheckSession") diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/entity/RecycleStationStaffEntity.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/entity/RecycleStationStaffEntity.java index f5b439a..8195a06 100644 --- a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/entity/RecycleStationStaffEntity.java +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/entity/RecycleStationStaffEntity.java @@ -57,4 +57,7 @@ public class RecycleStationStaffEntity { private String tenantId; @TableField("F_FLOW_ID") private String flowId; + + @TableField("openid") + private String openid; } diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffForm.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffForm.java index eea837f..fd570ab 100644 --- a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffForm.java +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffForm.java @@ -38,4 +38,6 @@ public class RecycleStationStaffForm { /** 自动接单 **/ @JsonProperty("autoEnabled") private Integer autoEnabled; + @JsonProperty("openid") + private String openid; } diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffPagination.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffPagination.java index f484fe7..72182e8 100644 --- a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffPagination.java +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/recyclestationstaff/RecycleStationStaffPagination.java @@ -36,4 +36,7 @@ public class RecycleStationStaffPagination extends Pagination { /** 回收员手机 */ @JsonProperty("mobilePhone") private Object mobilePhone; + + @JsonProperty("openid") + private String openid; } diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/AuthUserDto.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/AuthUserDto.java new file mode 100644 index 0000000..b037e13 --- /dev/null +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/AuthUserDto.java @@ -0,0 +1,96 @@ +package jnpf.model.wx; + +import jnpf.entity.RecycleStationStaffEntity; +import lombok.Data; + +@Data +public class AuthUserDto { + /** + * 授权类型:0--WEB端 1--微信端 + */ + private Integer authType; + + /** + * 用户名 + */ + private String userName; + + /** + * 密码 + */ + private String password; + + /** + * 传入参数:临时登录凭证 + */ + private String code; + + /** + * 用户登录id + */ + private String uuid = ""; + + //********************************** + //以下为微信类传输字段 + + /** + * 微信openId + */ + private String openId; + + /** + * 传入参数: 用户非敏感信息 + */ + private String rawData; + + /** + * 传入参数: 签名 + */ + private String signature; + + /** + * 传入参数: 用户敏感信息 + */ + private String encryptedData; + + /** + * 传入参数: 解密算法的向量 + */ + private String iv; + + /** + * 会话密钥 + */ + private String sessionKey; + + /** + * 用户在开放平台的唯一标识符 + */ + private String unionId; + + //以上为微信类传输字段 + //********************************** + + /** + * 返回:服务器jwt token + */ + private String token; + + /** + * 返回:userName或openId对应的用户 + */ + private RecycleStationStaffEntity userInfo; + + @Override + public String toString() { + return "AuthUser{" + + "userName='" + userName + '\'' + + ", password='" + "*********" + '\'' + + ", code='" + code + '\'' + + ", uuid='" + uuid + '\'' + + ", openId='" + openId + '\'' + + ", token='" + token + '\'' + + ", userInfo=" + userInfo + + '}'; + } +} diff --git a/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/WeChatUtil.java b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/WeChatUtil.java new file mode 100644 index 0000000..ac7525b --- /dev/null +++ b/jnpf-java-boot/jnpf-scm/jnpf-scm-entity/src/main/java/jnpf/model/wx/WeChatUtil.java @@ -0,0 +1,174 @@ +package jnpf.model.wx; + +import cn.hutool.core.codec.Base64; +import com.alibaba.fastjson.JSONObject; +import com.sun.net.ssl.HttpsURLConnection; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.security.Security; +import java.util.Arrays; + +/** + * 微信小程序工具类 + * + * @author zhuhuix + * @date 2019-12-25 + */ +public class WeChatUtil { + + public static String httpRequest(String requestUrl, String requestMethod, String output) { + try { + URL url = new URL(requestUrl); + HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setRequestMethod(requestMethod); + if (null != output) { + OutputStream outputStream = connection.getOutputStream(); + outputStream.write(output.getBytes(StandardCharsets.UTF_8)); + outputStream.close(); + } + // 从输入流读取返回内容 + InputStream inputStream = connection.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader); + String str; + StringBuilder buffer = new StringBuilder(); + while ((str = bufferedReader.readLine()) != null) { + buffer.append(str); + } + bufferedReader.close(); + inputStreamReader.close(); + inputStream.close(); + connection.disconnect(); + return buffer.toString(); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + public static String decryptData(String encryptDataB64, String sessionKeyB64, String ivB64) { + return new String( + decryptOfDiyIv( + Base64.decode(encryptDataB64), + Base64.decode(sessionKeyB64), + Base64.decode(ivB64) + ) + ); + } + + private static final String KEY_ALGORITHM = "AES"; + private static final String ALGORITHM_STR = "AES/CBC/PKCS7Padding"; + private static Key key; + private static Cipher cipher; + + private static void init(byte[] keyBytes) { + // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要 + int base = 16; + if (keyBytes.length % base != 0) { + int groups = keyBytes.length / base + 1; + byte[] temp = new byte[groups * base]; + Arrays.fill(temp, (byte) 0); + System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length); + keyBytes = temp; + } + // 初始化 + Security.addProvider(new BouncyCastleProvider()); + // 转化成JAVA的密钥格式 + key = new SecretKeySpec(keyBytes, KEY_ALGORITHM); + try { + // 初始化cipher + cipher = Cipher.getInstance(ALGORITHM_STR, "BC"); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 解密方法 + * + * @param encryptedData 要解密的字符串 + * @param keyBytes 解密密钥 + * @param ivs 自定义对称解密算法初始向量 iv + * @return 解密后的字节数组 + */ + private static byte[] decryptOfDiyIv(byte[] encryptedData, byte[] keyBytes, byte[] ivs) { + byte[] encryptedText = null; + init(keyBytes); + try { + cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivs)); + encryptedText = cipher.doFinal(encryptedData); + } catch (Exception e) { + e.printStackTrace(); + } + return encryptedText; + } + + /** + * 向指定 URL 发送POST方法的请求 + * + * @param url 发送请求的 URL + * @param json 请求参数,请求参数应该是 json 的形式。 + * @return 所代表远程资源的响应结果 + */ + public static String httpPost(String url, JSONObject json) { + PrintWriter out = null; + BufferedReader in = null; + String result = ""; + try { + URL realUrl = new URL(url); + // 打开和URL之间的连接 + URLConnection conn = realUrl.openConnection(); + // 设置通用的请求属性 + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + 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(json); + // flush输出流的缓冲 + out.flush(); + // 定义BufferedReader输入流来读取URL的响应 + in = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + String line; + while ((line = in.readLine()) != null) { + result=result.concat(line); + } + } catch (Exception e) { + System.out.println("发送 POST 请求出现异常!" + e); + e.printStackTrace(); + } + //使用finally块来关闭输出流、输入流 + finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + return result; + } + +} \ No newline at end of file diff --git a/jnpf-java-boot/jnpf-web/src/utils/apiUrl.js b/jnpf-java-boot/jnpf-web/src/utils/apiUrl.js index 040e5bf..caacbd6 100644 --- a/jnpf-java-boot/jnpf-web/src/utils/apiUrl.js +++ b/jnpf-java-boot/jnpf-web/src/utils/apiUrl.js @@ -8,7 +8,7 @@ */ module.exports = { // 开发环境接口配置 - APIURl: 'http://localhost:30000' + APIURl: 'http://127.0.0.1:30000' // 测试环境接口配置 //APIURl: 'http://222.71.165.187:30000' } diff --git a/jnpf-java-boot/jnpf-web/vue.config.js b/jnpf-java-boot/jnpf-web/vue.config.js index 17f6bd0..38dfd2c 100644 --- a/jnpf-java-boot/jnpf-web/vue.config.js +++ b/jnpf-java-boot/jnpf-web/vue.config.js @@ -15,7 +15,7 @@ const name = defaultSettings.title || 'JNPF快速开发平台' // page title // For example, Mac: sudo npm run // You can change the port by the following method: // port = 3000 npm run dev OR npm run dev --port = 3000 -const port = process.env.port || process.env.npm_config_port || 3000 // dev port +const port = process.env.port || process.env.npm_config_port || 4000 // dev port //const port = process.env.port || process.env.npm_config_port || 4000 // test port // All configuration item explanations can be find in https://cli.vuejs.org/config/