diff --git a/lib/EmergencyService/zdxtEmergencyBootStart/src/main/resources/templates/project/user/view.html b/lib/EmergencyService/zdxtEmergencyBootStart/src/main/resources/templates/project/user/view.html new file mode 100644 index 00000000..9015d727 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyBootStart/src/main/resources/templates/project/user/view.html @@ -0,0 +1,99 @@ + + + + + + +
+
+
+
+
+ +
+
+
+ +
+ +
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/controller/WechatLoginController.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/controller/WechatLoginController.java new file mode 100755 index 00000000..64893759 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/controller/WechatLoginController.java @@ -0,0 +1,63 @@ +package com.zdxt.knowledge.controller; + +import com.zdxt.common.controller.BaseController; +import com.zdxt.common.util.TableDataInfo; +import com.zdxt.knowledge.domain.WechatLoginRequest; +import com.zdxt.knowledge.domain.WechatUser; +import com.zdxt.knowledge.service.WechatService; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + + +/** + * 【请填写功能名称】Controller + * + * @author ruoyi + * @date 2023-01-23 + */ +@Controller +@RequestMapping("/small/wechat") +public class WechatLoginController extends BaseController { + + @Autowired + private WechatService wechatService; + + private String prefix = "project/user"; + + @RequiresPermissions("project:user:view") + @GetMapping("/view") + public String view() { + return prefix + "/view"; + } + + + /** + * 查询 + */ + @RequiresPermissions("project:user:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(WechatUser wechatUser) { + startPage(); + List list = wechatService.selectList(wechatUser); + return getDataTable(list); + } + + /** + * 登入 + */ + @ApiOperation(value = "登入接口", httpMethod = "POST") + @PostMapping("/login") + @ResponseBody + public Map login(@Validated @RequestBody WechatLoginRequest loginRequest) throws Exception { + Map userInfoMap = wechatService.getUserInfoMap(loginRequest); + return userInfoMap; + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/RawDataDO.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/RawDataDO.java new file mode 100644 index 00000000..2af3e042 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/RawDataDO.java @@ -0,0 +1,60 @@ +package com.zdxt.knowledge.domain; + +import java.io.Serializable; + +public class RawDataDO implements Serializable { + private String nickName; + private String avatarUrl; + private Integer gender; + private String city; + private String country; + private String province; + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public Integer getGender() { + return gender; + } + + public void setGender(Integer gender) { + this.gender = gender; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatLoginRequest.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatLoginRequest.java new file mode 100644 index 00000000..ba6abfa5 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatLoginRequest.java @@ -0,0 +1,63 @@ +package com.zdxt.knowledge.domain; + +import io.swagger.annotations.ApiModelProperty; + +import java.io.Serializable; + +public class WechatLoginRequest implements Serializable { + + @ApiModelProperty(value = "微信code", required = true) + private String code; + + @ApiModelProperty(value = "用户非敏感字段") + private String rawData; + + @ApiModelProperty(value = "签名") + private String signature; + + @ApiModelProperty(value = "用户敏感字段") + private String encryptedData; + + @ApiModelProperty(value = "解密向量") + private String iv; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getRawData() { + return rawData; + } + + public void setRawData(String rawData) { + this.rawData = rawData; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public String getEncryptedData() { + return encryptedData; + } + + public void setEncryptedData(String encryptedData) { + this.encryptedData = encryptedData; + } + + public String getIv() { + return iv; + } + + public void setIv(String iv) { + this.iv = iv; + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatUser.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatUser.java new file mode 100644 index 00000000..7f0ca7b9 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/domain/WechatUser.java @@ -0,0 +1,138 @@ +package com.zdxt.knowledge.domain; + +import java.io.Serializable; +import java.util.Date; + +public class WechatUser implements Serializable { + private static final long serialVersionUID = 1L; + + private String guid; + + private String token; + + private String nickname; + + private String avatarUrl; + + private Integer gender; + + private String country; + + private String province; + + private String city; + + private String mobile; + + private String openId; + + private String unionId; + + private String creator; + + private Date createTime; + + public String getGuid() { + return guid; + } + + public void setGuid(String guid) { + this.guid = guid; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public Integer getGender() { + return gender; + } + + public void setGender(Integer gender) { + this.gender = gender; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getProvince() { + return province; + } + + public void setProvince(String province) { + this.province = province; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getUnionId() { + return unionId; + } + + public void setUnionId(String unionId) { + this.unionId = unionId; + } + + public String getCreator() { + return creator; + } + + public void setCreator(String creator) { + this.creator = creator; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/mapper/WechatLoginMapper.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/mapper/WechatLoginMapper.java new file mode 100644 index 00000000..f556798f --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/mapper/WechatLoginMapper.java @@ -0,0 +1,23 @@ +package com.zdxt.knowledge.mapper; + +import com.zdxt.knowledge.domain.WechatUser; + +import java.util.List; + +/** + * Mapper接口 + * + * @author ruoyi + * @date 2023-12-26 + */ +public interface WechatLoginMapper { + + public List selectList(WechatUser wechatUser); + + public WechatUser getByOpenId(String openId); + + public int insertUser(WechatUser wechatUser); + + public int updateByOpenId(WechatUser wechatUser); + +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/WechatService.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/WechatService.java new file mode 100644 index 00000000..c361d73a --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/WechatService.java @@ -0,0 +1,27 @@ +package com.zdxt.knowledge.service; + +import com.zdxt.knowledge.domain.WechatLoginRequest; +import com.zdxt.knowledge.domain.WechatUser; + +import java.util.List; +import java.util.Map; + +/** + * Service接口 + * + * @author ruoyi + * @date 2023-01-23 + */ +public interface WechatService { + + public List selectList(WechatUser wechatUser); + + /** + * 登陆 + * + * @param loginRequest + * @return 集合 + */ + Map getUserInfoMap(WechatLoginRequest loginRequest) throws Exception; + +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/impl/WechatServiceImpl.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/impl/WechatServiceImpl.java new file mode 100644 index 00000000..9961707c --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/service/impl/WechatServiceImpl.java @@ -0,0 +1,198 @@ +package com.zdxt.knowledge.service.impl; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.zdxt.common.util.StringUtils; +import com.zdxt.knowledge.domain.RawDataDO; +import com.zdxt.knowledge.domain.WechatLoginRequest; +import com.zdxt.knowledge.domain.WechatUser; +import com.zdxt.knowledge.mapper.WechatLoginMapper; +import com.zdxt.knowledge.service.WechatService; +import com.zdxt.knowledge.utils.HttpClientUtils; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Base64; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.AlgorithmParameters; +import java.security.Security; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Service业务层处理 + * + * @author ruoyi + * @date 2023-01-23 + */ +@Service +@Slf4j +public class WechatServiceImpl implements WechatService { + + @Autowired + private WechatLoginMapper wechatLoginMapper; + + private static final String REQUEST_URL = "https://api.weixin.qq.com/sns/jscode2session"; + private static final String APPID = "wx93ec514a5c456507"; + private static final String SECRET = "f5a3f295dbee3cc1c2f73b9a324c2eb2"; + private static final String GRANT_TYPE = "authorization_code"; + + + @Override + public List selectList(WechatUser wechatUser) { + return wechatLoginMapper.selectList(wechatUser); + } + + @Override + public Map getUserInfoMap(WechatLoginRequest loginRequest) throws Exception { + Map userInfoMap = new HashMap<>(); + log.info("Start get SessionKey,loginRequest的数据为:" + JSONObject.toJSONString(loginRequest)); + JSONObject sessionKeyOpenId = getSessionKeyOrOpenId(loginRequest.getCode()); + Assert.isTrue(sessionKeyOpenId != null, "获取sessionKeyOpenId出错"); + + // 获取openId && sessionKey + String openId = sessionKeyOpenId.getString("openid"); + Assert.isTrue(openId != null, "获取openId出错"); + String sessionKey = sessionKeyOpenId.getString("session_key"); + WechatUser insertOrUpdateDO = buildWechatUserAuthInfoDO(loginRequest, openId, sessionKey); + + // 根据code保存openId和sessionKey + JSONObject sessionObj = new JSONObject(); + sessionObj.put("openId", openId); + sessionObj.put("sessionKey", sessionKey); + // 这里的set方法使用Redis,key自行替换,10表示10天 +// stringJedisClientTem.set(WechatRedisPrefixConstant.USER_OPPEN_ID_AND_SESSION_KEY_PREFIX + loginRequest.getCode(), +// sessionObj.toJSONString(), 10, TimeUnit.DAYS); + + // 根据openid查询用户 + WechatUser user = wechatLoginMapper.getByOpenId(openId); + + if (user == null) { + // 用户不存在,insert用户,这里加了个分布式锁,防止insert重复用户 +// if (setLock(WechatRedisPrefixConstant.INSERT_USER_DISTRIBUTED_LOCK_PREFIX + openId, "1", 10)) { +// // 用户入库 +// insertOrUpdateDO.setToken(getToken()); +// wechatLoginMapper.insertUser(insertOrUpdateDO); +// userInfoMap.put("token", insertOrUpdateDO.getToken()); +// } + insertOrUpdateDO.setGuid(StringUtils.getUUID()); + insertOrUpdateDO.setCreator("SYSTEM"); + insertOrUpdateDO.setToken(getToken(insertOrUpdateDO.getGuid(),insertOrUpdateDO.getNickname())); + wechatLoginMapper.insertUser(insertOrUpdateDO); + userInfoMap.put("token", insertOrUpdateDO.getToken()); + } else { + userInfoMap.put("token", user.getToken()); + // 已存在,做已存在的处理,如更新用户的头像,昵称等,根据openID更新 + wechatLoginMapper.updateByOpenId(insertOrUpdateDO); + } + + return userInfoMap; + } + + private JSONObject getSessionKeyOrOpenId(String code) throws Exception { + +// String apiUrl = StrUtil.format("https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code", APPID, SECRET, code); +// String body = HttpRequest.get(apiUrl).execute().body(); + + Map requestUrlParam = new HashMap<>(); + // 小程序appId + requestUrlParam.put("appid", APPID); + // 小程序secret + requestUrlParam.put("secret", SECRET); + // 小程序端返回的code + requestUrlParam.put("js_code", code); + // 默认参数 + requestUrlParam.put("grant_type", GRANT_TYPE); + + // 发送post请求读取调用微信接口获取openid用户唯一标识 + String result = HttpClientUtils.doPost(REQUEST_URL, requestUrlParam); + return JSON.parseObject(result); + } + + private WechatUser buildWechatUserAuthInfoDO(WechatLoginRequest loginRequest, String sessionKey, String openId) { + WechatUser wechatUserDO = new WechatUser(); + wechatUserDO.setOpenId(openId); + + if (loginRequest.getRawData() != null) { + RawDataDO rawDataDO = JSON.parseObject(loginRequest.getRawData(), RawDataDO.class); + wechatUserDO.setNickname(rawDataDO.getNickName()); + wechatUserDO.setAvatarUrl(rawDataDO.getAvatarUrl()); + wechatUserDO.setGender(rawDataDO.getGender()); + wechatUserDO.setCity(rawDataDO.getCity()); + wechatUserDO.setCountry(rawDataDO.getCountry()); + wechatUserDO.setProvince(rawDataDO.getProvince()); + } + + // 解密加密信息,获取unionID + if (loginRequest.getEncryptedData() != null) { + JSONObject encryptedData = getEncryptedData(loginRequest.getEncryptedData(), sessionKey, loginRequest.getIv()); + if (encryptedData != null) { + String unionId = encryptedData.getString("unionId"); + String phone = encryptedData.getString("phoneNumber"); + wechatUserDO.setUnionId(unionId); + } + } + + return wechatUserDO; + } + + private JSONObject getEncryptedData(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 + 1; + 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) { + log.error("解密加密信息报错", e.getMessage()); + } + return null; + } + +// private boolean setLock(String key, String value, long expire) throws Exception { +// boolean result = stringJedisClientTem.setNx(key, value, expire, TimeUnit.SECONDS); +// return result; +// } + + private String getToken(String guid, String nickname) throws Exception { + // 写入用户信息 + HashMap tokenMap = new HashMap<>(); + tokenMap.put("userName",nickname); + tokenMap.put("id",guid); + + // 生成token + //String token = JWTUtil.createToken(tokenMap,tokenKey.getBytes()); + return StringUtils.getUUID(); + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/utils/HttpClientUtils.java b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/utils/HttpClientUtils.java new file mode 100644 index 00000000..ae4743c5 --- /dev/null +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/java/com/zdxt/knowledge/utils/HttpClientUtils.java @@ -0,0 +1,70 @@ +package com.zdxt.knowledge.utils; + +import org.apache.http.NameValuePair; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class HttpClientUtils { + + final static int TIMEOUT = 1000; + + final static int TIMEOUT_MSEC = 5 * 1000; + + public static String doPost(String url, Map paramMap) throws IOException { + // 创建Httpclient对象 + CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + String resultString = ""; + + try { + // 创建Http Post请求 + HttpPost httpPost = new HttpPost(url); + + // 创建参数列表 + if (paramMap != null) { + List paramList = new ArrayList<>(); + for (Map.Entry param : paramMap.entrySet()) { + paramList.add(new BasicNameValuePair(param.getKey(), param.getValue())); + } + // 模拟表单 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList); + httpPost.setEntity(entity); + } + + httpPost.setConfig(builderRequestConfig()); + + // 执行http请求 + response = httpClient.execute(httpPost); + + resultString = EntityUtils.toString(response.getEntity(), "UTF-8"); + } catch (Exception e) { + throw e; + } finally { + try { + response.close(); + } catch (IOException e) { + throw e; + } + } + + return resultString; + } + + private static RequestConfig builderRequestConfig() { + return RequestConfig.custom() + .setConnectTimeout(TIMEOUT_MSEC) + .setConnectionRequestTimeout(TIMEOUT_MSEC) + .setSocketTimeout(TIMEOUT_MSEC).build(); + } +} diff --git a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/resources/mapper/SceneMedalMapper.xml b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/resources/mapper/SceneMedalMapper.xml index 13a32a0e..fa8804a2 100644 --- a/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/resources/mapper/SceneMedalMapper.xml +++ b/lib/EmergencyService/zdxtEmergencyKnowledgeService/src/main/resources/mapper/SceneMedalMapper.xml @@ -32,7 +32,6 @@ and name like concat('%', #{name}, '%') and creator = #{creator} - order by sort ASC + + + and `nickname` like concat('%', #{nickname}, '%') + and mobile = #{mobile} + + order by create_time ASC + + + + + + insert into wechat_user + + guid, + `token`, + nickname, + avatar_url, + gender, + country, + province, + `city`, + mobile, + creator, + create_time, + open_id, + union_id, + + + #{guid}, + #{token}, + #{nickname}, + #{avatarUrl}, + #{gender}, + #{country}, + #{province}, + #{city}, + #{mobile}, + #{creator}, + #{createTime}, + #{openId}, + #{unionId}, + + + + + update wechat_user + + token = #{token}, + nickname = #{nickname}, + avatar_url = #{avatarUrl}, + gender = #{gender}, + country = #{country}, + province = #{province}, + city = #{city}, + `mobile` = #{mobile}, + open_id = #{openId}, + union_id = #{unionId}, + + where guid = #{guid} + + + \ No newline at end of file