Commit 3ac41f48 authored by muhong's avatar muhong

新增 登录、小程序码、小程序链接支持支付宝、抖音

parent 8fe103fd
package com.wwdz.ch.db.dto.request;
import com.xxdxxs.entity.Entity;
import lombok.Data;
@Data
public class UserSearchRequestDto implements Entity {
private Long id;
private String mobile;
private String nickname;
}
...@@ -53,6 +53,12 @@ ...@@ -53,6 +53,12 @@
<artifactId>weixin-java-miniapp</artifactId> <artifactId>weixin-java-miniapp</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.34.0.ALL</version>
</dependency>
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId> <artifactId>springfox-swagger2</artifactId>
......
package com.wwdz.ch.wx.constant;
import java.util.HashMap;
import java.util.Map;
public enum LoginTypeEnum {
WECHAT(1, "微信"),
ALIPAY(2, "支付宝"),
TIKTOK(3, "抖音"),
;
private Integer code;
private String name;
LoginTypeEnum(Integer code, String name) {
this.code = code;
this.name = name;
}
public Integer getCode() {
return code;
}
public String getName() {
return name;
}
public static String getDesByCode(String code) {
for (LoginTypeEnum loginTypeEnum : LoginTypeEnum.values()) {
if (code.equals(loginTypeEnum.getCode())) {
return loginTypeEnum.getName();
}
}
return null;
}
/**
* 返回map
* @return
*/
public static Map<Integer, String> getLoginTypeEnumMap() {
Map<Integer, String> map = new HashMap<>();
for (LoginTypeEnum loginTypeEnum : LoginTypeEnum.values()) {
map.put(loginTypeEnum.getCode(), loginTypeEnum.getName());
}
return map;
}
}
...@@ -31,9 +31,16 @@ public class ItemRequestDto implements Entity { ...@@ -31,9 +31,16 @@ public class ItemRequestDto implements Entity {
private String detail; private String detail;
// 藏品价格 // 藏品价格
private String price; private String price;
// 当前页
private Integer page; private Integer page;
// 页面大小
private Integer size; private Integer size;
// 页面路径
private String path; private String path;
// 查看详情的入口类型(1、钱柜,2、足迹)
private Integer type; private Integer type;
// 页面路径
private String pageUrl; private String pageUrl;
// 环境类型(1、微信,2、支付宝,3、抖音)
private Integer loginType;
} }
...@@ -21,4 +21,6 @@ public class UserRequestDto implements Entity { ...@@ -21,4 +21,6 @@ public class UserRequestDto implements Entity {
private String encryptedData; private String encryptedData;
private String iv; private String iv;
private Integer type; private Integer type;
// 快捷登录方式(1、微信,2、支付宝,3、抖音)
private Integer loginType;
} }
...@@ -12,9 +12,12 @@ import com.wwdz.ch.db.dao.*; ...@@ -12,9 +12,12 @@ import com.wwdz.ch.db.dao.*;
import com.wwdz.ch.db.domain.*; import com.wwdz.ch.db.domain.*;
import com.wwdz.ch.db.dto.request.EsSearchRequestDto; import com.wwdz.ch.db.dto.request.EsSearchRequestDto;
import com.wwdz.ch.db.es.ItemEsDao; import com.wwdz.ch.db.es.ItemEsDao;
import com.wwdz.ch.wx.constant.LoginTypeEnum;
import com.wwdz.ch.wx.entity.request.ItemRequestDto; import com.wwdz.ch.wx.entity.request.ItemRequestDto;
import com.wwdz.ch.wx.entity.vo.AgentTranceResponseVo; import com.wwdz.ch.wx.entity.vo.AgentTranceResponseVo;
import com.wwdz.ch.wx.entity.vo.ItemResponseVo; import com.wwdz.ch.wx.entity.vo.ItemResponseVo;
import com.wwdz.ch.wx.manager.AlipayLoginManager;
import com.wwdz.ch.wx.manager.TikTokLoginManager;
import com.wwdz.ch.wx.manager.WxLoginManager; import com.wwdz.ch.wx.manager.WxLoginManager;
import com.wwdz.ch.wx.service.ItemService; import com.wwdz.ch.wx.service.ItemService;
import com.wwdz.ch.wx.util.StringUtil; import com.wwdz.ch.wx.util.StringUtil;
...@@ -59,6 +62,10 @@ public class ItemServiceImpl implements ItemService { ...@@ -59,6 +62,10 @@ public class ItemServiceImpl implements ItemService {
@Autowired @Autowired
private WxLoginManager wxLoginManager; private WxLoginManager wxLoginManager;
@Autowired @Autowired
private AlipayLoginManager alipayLoginManager;
@Autowired
private TikTokLoginManager tikTokLoginManager;
@Autowired
private QiniuStorage qiniuStorage; private QiniuStorage qiniuStorage;
@Autowired @Autowired
private UserDao userDao; private UserDao userDao;
...@@ -476,6 +483,7 @@ public class ItemServiceImpl implements ItemService { ...@@ -476,6 +483,7 @@ public class ItemServiceImpl implements ItemService {
String urlOfSize = qiniuStorage.generateUrl(keyName); String urlOfSize = qiniuStorage.generateUrl(keyName);
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
map.put("url", urlOfSize); map.put("url", urlOfSize);
logger.info("【请求结束】获取微信小程序码成功");
return Result.success(map); return Result.success(map);
} catch (Exception e) { } catch (Exception e) {
logger.error("获取微信小程序码失败", e); logger.error("获取微信小程序码失败", e);
...@@ -483,6 +491,51 @@ public class ItemServiceImpl implements ItemService { ...@@ -483,6 +491,51 @@ public class ItemServiceImpl implements ItemService {
} }
} }
@Override
public Result getAcode(String page, String scene, Integer loginType, HttpServletResponse response) {
try {
String url = "";
if (loginType.equals(LoginTypeEnum.WECHAT.getCode())) {
// 判断是否存储过该请求路径的微信小程序码图片
String keyName = CommConsts.UPLOAD_PRE_WXACODE_DIRECTORY + page + "/" + scene + "." + MediaTypeEnum.IMAGE_JPG.getExt();
FileInfo fileInfo = (FileInfo) qiniuStorage.checkFile(keyName);
if (Objects.isNull(fileInfo)) {
InputStream inputStream = wxLoginManager.getWxacodeStream(page, scene);
if (Objects.isNull(inputStream)) {
return Result.failed("获取微信小程序流失败");
}
// 新生成微信小程序码并上传到七牛云
qiniuStorage.store(inputStream, 1, MediaTypeEnum.IMAGE_JPG.getMime(), keyName);
}
url = qiniuStorage.generateUrl(keyName);
}
if (loginType.equals(LoginTypeEnum.ALIPAY.getCode())) {
url = alipayLoginManager.getAcode(page, scene);
if (StringUtils.isBlank(url)) {
return Result.failed("获取支付宝小程序码失败");
}
}
if (loginType.equals(LoginTypeEnum.TIKTOK.getCode())) {
String clientToken = tikTokLoginManager.getClientToken();
if (StringUtils.isBlank(clientToken)) {
return Result.failed("获取token失败");
}
url = tikTokLoginManager.getAcode(clientToken, page, scene);
if (StringUtils.isBlank(url)) {
return Result.failed("获取抖音小程序码失败");
}
}
Map<String, Object> map = new HashMap<>();
map.put("url", url);
logger.info("【请求结束】获取小程序码成功");
return Result.success(map);
} catch (Exception e) {
logger.error("获取小程序码失败", e);
return Result.failed("获取小程序码失败");
}
}
@Override @Override
public Result getWxLink(String pageUrl) { public Result getWxLink(String pageUrl) {
try { try {
...@@ -499,6 +552,41 @@ public class ItemServiceImpl implements ItemService { ...@@ -499,6 +552,41 @@ public class ItemServiceImpl implements ItemService {
} }
} }
@Override
public Result getLink(String pageUrl, Integer loginType) {
try {
String link = "";
if (loginType.equals(LoginTypeEnum.WECHAT.getCode())) {
link = wxLoginManager.getLink(pageUrl);
if (StringUtils.isBlank(link)) {
return Result.failed("获取微信小程序链接失败");
}
}
if (loginType.equals(LoginTypeEnum.ALIPAY.getCode())) {
link = alipayLoginManager.getLink(pageUrl);
if (StringUtils.isBlank(link)) {
return Result.failed("获取支付宝小程序链接失败");
}
}
if (loginType.equals(LoginTypeEnum.TIKTOK.getCode())) {
String clientToken = tikTokLoginManager.getClientToken();
if (StringUtils.isBlank(clientToken)) {
return Result.failed("获取token失败");
}
link = tikTokLoginManager.getLink(clientToken, pageUrl);
if (StringUtils.isBlank(link)) {
return Result.failed("获取抖音小程序链接失败");
}
}
Map<String, Object> map = new HashMap<>();
map.put("link", link);
return Result.success(map);
} catch (Exception e) {
logger.error("获取小程序链接失败", e);
return Result.failed("获取小程序链接失败");
}
}
@Override @Override
public Result uploadImage(MultipartFile file) { public Result uploadImage(MultipartFile file) {
try { try {
......
...@@ -15,9 +15,12 @@ import com.wwdz.ch.db.dao.UserDao; ...@@ -15,9 +15,12 @@ import com.wwdz.ch.db.dao.UserDao;
import com.wwdz.ch.db.domain.User; import com.wwdz.ch.db.domain.User;
import com.wwdz.ch.db.dto.request.FavoritesRequestDto; import com.wwdz.ch.db.dto.request.FavoritesRequestDto;
import com.wwdz.ch.wx.constant.CacheCodeConstants; import com.wwdz.ch.wx.constant.CacheCodeConstants;
import com.wwdz.ch.wx.constant.LoginTypeEnum;
import com.wwdz.ch.wx.dao.UserInfo; import com.wwdz.ch.wx.dao.UserInfo;
import com.wwdz.ch.wx.dao.UserToken; import com.wwdz.ch.wx.dao.UserToken;
import com.wwdz.ch.wx.entity.request.UserRequestDto; import com.wwdz.ch.wx.entity.request.UserRequestDto;
import com.wwdz.ch.wx.manager.AlipayLoginManager;
import com.wwdz.ch.wx.manager.TikTokLoginManager;
import com.wwdz.ch.wx.manager.UserTokenManager; import com.wwdz.ch.wx.manager.UserTokenManager;
import com.wwdz.ch.wx.manager.WxLoginManager; import com.wwdz.ch.wx.manager.WxLoginManager;
import com.wwdz.ch.wx.service.FavoritesService; import com.wwdz.ch.wx.service.FavoritesService;
...@@ -60,6 +63,10 @@ public class UserServiceImpl implements UserService { ...@@ -60,6 +63,10 @@ public class UserServiceImpl implements UserService {
@Autowired @Autowired
private WxLoginManager wxLoginManager; private WxLoginManager wxLoginManager;
@Autowired @Autowired
private AlipayLoginManager alipayLoginManager;
@Autowired
private TikTokLoginManager tikTokLoginManager;
@Autowired
private RedisUtil redisUtil; private RedisUtil redisUtil;
@Value("${avatar-url}") @Value("${avatar-url}")
...@@ -68,45 +75,6 @@ public class UserServiceImpl implements UserService { ...@@ -68,45 +75,6 @@ public class UserServiceImpl implements UserService {
private AliSmsSender aliSmsSender; private AliSmsSender aliSmsSender;
@Transactional
@Override
public Result loginByWx(UserRequestDto dto, HttpServletRequest request) {
try {
String mobile = "";
try {
mobile = wxLoginManager.getPhone(dto);
if (StringUtils.equals("false", mobile)) {
return Result.failed("获取access_token失败");
}
if (StringUtils.equals("sessionFalse", mobile)) {
return Result.failed("获取sessionKey失败");
}
if (StringUtils.equals("phoneFalse", mobile)) {
return Result.failed("获取手机号失败");
}
if (StringUtils.equals("decryptFalse", mobile)) {
return Result.failed(ResultCode.FAILED.getCode(), "用户信息解密失败");
}
} catch (Exception e) {
logger.error("获取微信用户手机号失败", e);
return Result.failed("获取微信用户手机号失败");
}
if (StringUtils.isBlank(mobile)) {
logger.error("获取微信用户手机号失败");
return Result.failed("获取微信用户手机号失败");
}
// 获取登录结果
Map<String, Object> result = getLoginResult(mobile, request);
logger.info("【请求结束】手机号登录,响应结果:{}", JSONObject.toJSONString(result));
return Result.success(result);
} catch (Exception e) {
logger.error("微信快捷登录失败", e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return Result.failed("微信快捷登录失败");
}
}
@Override @Override
public Result regCaptcha(UserRequestDto dto) { public Result regCaptcha(UserRequestDto dto) {
try { try {
...@@ -172,6 +140,98 @@ public class UserServiceImpl implements UserService { ...@@ -172,6 +140,98 @@ public class UserServiceImpl implements UserService {
} }
} }
@Transactional
@Override
public Result login(UserRequestDto dto, HttpServletRequest request) {
try {
String mobile = "";
try {
if (dto.getLoginType().equals(LoginTypeEnum.WECHAT.getCode())) {
mobile = wxLoginManager.getPhone(dto);
if (StringUtils.equals("false", mobile)) {
return Result.failed("获取access_token失败");
}
if (StringUtils.equals("sessionFalse", mobile)) {
return Result.failed("获取sessionKey失败");
}
if (StringUtils.equals("phoneFalse", mobile)) {
return Result.failed("获取手机号失败");
}
if (StringUtils.equals("decryptFalse", mobile)) {
return Result.failed(ResultCode.FAILED.getCode(), "用户信息解密失败");
}
}
if (dto.getLoginType().equals(LoginTypeEnum.ALIPAY.getCode())) {
mobile = alipayLoginManager.getPhone(dto.getEncryptedData());
if (StringUtils.equals("false", mobile)) {
return Result.failed("用户信息解密失败");
}
}
if (dto.getLoginType().equals(LoginTypeEnum.TIKTOK.getCode())) {
String sessionKey = tikTokLoginManager.getSessionKey(dto.getCode());
if (StringUtils.isBlank(sessionKey)) {
return Result.failed("获取sessionKey失败");
}
mobile = tikTokLoginManager.getPhone(dto.getEncryptedData(), sessionKey, dto.getIv());
if (StringUtils.equals("false", mobile)) {
return Result.failed("用户信息解密失败");
}
}
} catch (Exception e) {
logger.error("获取用户手机号异常", e);
return Result.failed("获取用户手机号失败");
}
// 获取登录结果
Map<String, Object> result = getLoginResult(mobile, request);
logger.info("【请求结束】快捷登录成功,响应结果:{}", JSONObject.toJSONString(result));
return Result.success(result);
} catch (Exception e) {
logger.error("快捷登录失败", e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return Result.failed("快捷登录失败");
}
}
@Transactional
@Override
public Result loginByWx(UserRequestDto dto, HttpServletRequest request) {
try {
String mobile = "";
try {
mobile = wxLoginManager.getPhone(dto);
if (StringUtils.equals("false", mobile)) {
return Result.failed("获取access_token失败");
}
if (StringUtils.equals("sessionFalse", mobile)) {
return Result.failed("获取sessionKey失败");
}
if (StringUtils.equals("phoneFalse", mobile)) {
return Result.failed("获取手机号失败");
}
if (StringUtils.equals("decryptFalse", mobile)) {
return Result.failed(ResultCode.FAILED.getCode(), "用户信息解密失败");
}
} catch (Exception e) {
logger.error("获取微信用户手机号失败", e);
return Result.failed("获取微信用户手机号失败");
}
if (StringUtils.isBlank(mobile)) {
logger.error("获取微信用户手机号失败");
return Result.failed("获取微信用户手机号失败");
}
// 获取登录结果
Map<String, Object> result = getLoginResult(mobile, request);
logger.info("【请求结束】手机号登录,响应结果:{}", JSONObject.toJSONString(result));
return Result.success(result);
} catch (Exception e) {
logger.error("微信快捷登录失败", e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
return Result.failed("微信快捷登录失败");
}
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public Result updateProfile(UserRequestDto dto) { public Result updateProfile(UserRequestDto dto) {
......
package com.wwdz.ch.wx.manager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayOpenAppQrcodeCreateRequest;
import com.alipay.api.response.AlipayOpenAppQrcodeCreateResponse;
import com.xxdxxs.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import java.net.URLEncoder;
import java.util.Map;
/**
* 支付宝小程序服务
*/
@Service
public class AlipayLoginManager {
private static final Logger logger = LoggerFactory.getLogger(AlipayLoginManager.class);
// 支付宝小程序对应的appid
private static final String appid = "2021004108672867";
// 支付宝小程序对应的支付宝公钥
private static final String signVeriKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgUwrLm4n13ixVgq1nUS3Aggieny0yxl8uiwNEKNNoL8MZnvrKmZSFAgr8m7384OLuElo2CXTTMZWCNeGo7If+qb1whCBsrGBfWAjrEdFlTNirWINaoS9F/fvJPRQ/biFryvhvP/AJewkAA2NuxZwbYpelw6zc+lNF0bGiSBujAawFs1Ok2SQMMk4javXvUwibx7u+aiSCDOy7IaZW+Rv6wVfeHT2uHIDKvOYyitdmjiJikuIzvILeZs4sZwlZvWEbEa1bPmAhi5ZZsh62Nt7Xd3OnMvcj9VK9xkJGJ3Dgx3MmAC54kDl0CST9a4sdRRbMi4gd7v+K8e484TQdHjQMwIDAQAB";
// 支付宝小程序对应的加解密密钥
private static final String decryptKey = "kpeGeMSDTQZWyheHWt4Iwg==";
// 支付宝小程序对应的应用私钥
private static final String privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDltXUqBWcnmTt8O/vc8Br9hF87mKB3+9KQ5jN9Oh8FCs0J+0mED+ggBKLhNCsBb+uyu+MHqs5kBYDTwqp5fDPTyW37RklvfpHcf9HO9o1V7+C+t7qA2GLaXl/G5JDjpIipd+sHLj/yPw5DsTuMi8HUwb+ninSoil0Bg2QqTYL/2TiAfJ3+3s7nKIrjuEUmd47qFfpoyyPP0ZY+3E57M+vkklEvFWy8dCCvEh9bZY4ebVS4IUMLyhATpCqn8ESOjlkaIC4rAuTLhr52+hNsQUGzeVcKmpKGYm4YEhKaiwGW0MecjFd5wLj/ThPNnHNk23CwVfgN74ISu5UwibSHNzydAgMBAAECggEANw2tXfvbhD8SZa0OqR4Wqen+1Q64buk4xyeU8Y9rfc7f42OJdBBH5tyVmPni0L5dNAIZ4G2Md6ZmANqn9uPQnBKrvExVL1abaMhtpXer2gvaxnrMRTMXRhTWSZngK970LgGin57zDoEUTx78EawxMWeaInJpkTdQIRu3dvgKzHxz2uuWPXvRWTsgHrOcya7tjB05aQDJvPmZIfduER170kRw+nkhNLYoaYnfvlG5lBS+Nbw9wJmIt1VziET+anBEjCiQAxZdefsw2O9+N27MR8dToOyY2/03rzByuSZav204D6BG9Ggs47ogfvoszFYzXxedqj8WNXmtW59za++XNQKBgQD8q6WzgKdFp9mdZp0O9WfbYwUnrTnijRIJo6if2YMUipN/nbsEo50MDeWMEVfxrW+JYkgcL5xU6FDtPwoR5uN31NaFluuqSCoOdVtTUgpdNIMIDKbmplr5b8WuF7Ng0mSi9FYhRqbkQS0Lk412/eUxvXWIcyhUnbb3cqGPart/ZwKBgQDovFods6BF1gdfKDIWNZB4wTCUkQ7KOHmHfuHdAhZVMjC0R+TqjXMi6Xgt6N/D4wbJSk00iX3qGDynAxcltPjieER9Nsafm1vb7br+P+mcIz2j61GrDPZ2MvraUq3XJHxzM7BC7xGpISyukTY4UsSjW9r2sENyKYqsfK74HwaVWwKBgFuPxBNBStx2D+j3F3ElQwaAYozXPEO5xVCS6vdKNjMKaJr1SKFMvQtyOb3BRzJAHEwXvnPgWPF34mOm1XpZRhLVoQt1/l6Nmhf1NSwDbdgKwHT5SL4KiKsdcvA8jHdIpslaa5/RX4cVi0JHrRrytMyKkH3q5TGMmZIgCyXSkrF/AoGAa7KVZP81YHu9Z4xbOSnKVAbaKzXBCVT+7/OII1SO7xfNr+9BAEU6jWJKibwkqCoLfuRSO8iQKt7SWlq0wG8xaONMlkDdwwgKhwhIqtT6jpVENfF0FlpmRqYqrRLrfQ5WRJ0bqK2ml4RRf+qUk5XBhvK/rb49R7vvfwgnk4wP6NcCgYBnyaWUQU4tImWXBsIZ8OPZLcjYRmELg43BwYYU3S4vh2NIQAZnPXS56yobTPFGSntDUA3ESxsls60eKeBc1PSPPFOnTuXHs+tx/7AfuvG+pebRKauVXu9hcASvrBZcJoAirYhMKaMmoxdsodMhAc2ttzZyomLpplia1VcmI8NQ4A==";
// 支付宝小程序链接前缀
private static final String linkPrefix = "alipays://platformapi/startapp?appId=%s";
// 支付宝小程序调起前缀
private static final String openUrlPrefix = "https://ds.alipay.com/?scheme=%s";
/**
* 解密获取手机号
*
* @param response
* @return
*/
public String getPhone(String response) {
logger.info("开始解密获取支付宝小程序手机号");
// 获取验签和解密所需要的参数
Map<String, String> openapiResult = JSON.parseObject(response,new TypeReference<Map<String, String>>() {}, Feature.OrderedField);
String signType = "RSA2";
String charset = "UTF-8";
String encryptType = "AES";
String sign = openapiResult.get("sign");
String content = openapiResult.get("response");
// 判断是否为加密内容
boolean isDataEncrypted = !content.startsWith("{");
if (!isDataEncrypted) {
logger.info("支付宝解密失败,不是加密内容");
return "false";
}
boolean signCheckPass = false;
// 验签
String signContent = "\"" + content + "\"";
try {
signCheckPass = AlipaySignature.rsaCheck(signContent, sign, signVeriKey, charset, signType);
} catch (AlipayApiException e) {
logger.error("支付宝解密失败,验签异常", e);
return "false";
}
if (!signCheckPass) {
logger.info("支付宝解密失败,验签不通过");
return "false";
}
// 解密
String plainData = null;
try {
plainData = AlipayEncrypt.decryptContent(content, encryptType, decryptKey, charset);
} catch (AlipayApiException e) {
logger.error("支付宝解密失败,解密异常", e);
return "false";
}
if (StringUtils.isBlank(plainData) || !plainData.contains("mobile")) {
logger.info("支付宝解密失败,解密不通过");
return "false";
}
return JsonUtils.getValueByPath(plainData, "mobile");
}
/**
* 获取二维码
*
* @param page
* @param scene
* @return
*/
public String getAcode(String page, String scene) {
logger.info("开始调用支付宝生成小程序码接口");
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appid, privateKey,"json","UTF8", signVeriKey,"RSA2");
AlipayOpenAppQrcodeCreateRequest request = new AlipayOpenAppQrcodeCreateRequest();
request.setBizContent("{" +
" \"url_param\":\"" + page + "\"," +
" \"query_param\":\"" + scene +"\"," +
" \"describe\":\"藏品分享\"," +
" \"color\":\"0x00BFFF\"," +
" \"size\":\"m\"" +
"}");
try {
AlipayOpenAppQrcodeCreateResponse response = alipayClient.execute(request);
logger.info("调用支付宝生成小程序码接口的结果:" + JSON.toJSONString(response));
if (response.isSuccess()) {
logger.info("调用支付宝生成小程序码成功");
return response.getQrCodeUrlCircleBlue();
}
} catch (Exception e) {
logger.error("调用支付宝生成小程序码失败", e);
}
logger.info("调用支付宝生成小程序码失败");
return null;
}
/**
* 获取链接
*
* @param pageUrl
* @return
*/
public String getLink(String pageUrl) {
try {
String[] page = pageUrl.split("\\?");
String encodeQuery = URLEncoder.encode(page[1], "UTF-8");
String link = String.format(linkPrefix, appid + "&page=" + page[0] + "?" + encodeQuery);
return String.format(openUrlPrefix, URLEncoder.encode(link, "UTF-8"));
} catch (Exception e) {
logger.info("获取支付宝小程序链接失败");
}
return null;
}
}
package com.wwdz.ch.wx.manager;
import com.alibaba.fastjson.JSON;
import com.wwdz.ch.core.util.OkHttpUtil;
import com.xxdxxs.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.util.Base64;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* 抖音小程序服务
*/
@Service
public class TikTokLoginManager {
private static final Logger logger = LoggerFactory.getLogger(TikTokLoginManager.class);
@Autowired
private ApplicationContext applicationContext;
// appid
private static final String appid = "ttc1fcb7415ec18f6f01";
// appSecret
private static final String appSecret = "1a248c43d69c4bcba48779efac2c6f3ade573ec7";
// 抖音小程序获取session_key的api正式环境
private static final String SANDBOX_SESSION_KEY_URL = "https://developer.toutiao.com/api/apps/v2/jscode2session";
// 抖音小程序获取session_key的api沙箱环境
private static final String PROD_SESSION_KEY_URL = "https://open-sandbox.douyin.com/api/apps/v2/jscode2session";
// 抖音小程序获取client_token的api正式环境
private static final String SANDBOX_CLIENT_TOKEN_URL = "https://open-sandbox.douyin.com/oauth/client_token/";
// 抖音小程序获取client_token的api沙箱环境
private static final String PROD_CLIENT_TOKEN_URL = "https://open.douyin.com/oauth/client_token/";
// 抖音小程序二维码地址
private static final String GET_ACODE_URL = "https://open.douyin.com/api/apps/v1/qrcode/create/";
// 抖音小程序链接地址
private static final String GET_LINK_URL = "https://open.douyin.com/api/apps/v1/url_link/generate";
/**
* 获取用户登录后的session_key
*
* @param code
* @return
*/
public String getSessionKey(String code) {
try {
logger.info("开始获取抖音小程序的session_key");
String activeProfile = applicationContext.getEnvironment().getActiveProfiles()[0];
String url = SANDBOX_SESSION_KEY_URL;
if (!StringUtils.equals("dev", activeProfile)) {
url = PROD_SESSION_KEY_URL;
}
Map<String, Object> param = new HashMap<>();
param.put("appid", appid);
param.put("secret", appSecret);
param.put("code", code);
String result = OkHttpUtil.builder().url(url)
.addParams(param)
.post(true).sync();
logger.info("获取抖音小程序session_key的结果:" + result);
if (!StringUtils.equals("0", JsonUtils.getValueByPath(result, "err_no"))) {
logger.info("获取抖音小程序session_key失败");
return null;
}
return JsonUtils.getValueByPath(result, "data/session_key");
} catch (Exception e) {
logger.error("获取抖音小程序session_key异常", e);
return null;
}
}
/**
* 解密获取手机号
*
* @param encryptedData
* @param sessionKey
* @param iv
* @return
*/
public String getPhone (String encryptedData, String sessionKey, String iv) {
try {
logger.info("开始进行抖音解密手机号");
Base64.Decoder decoder = Base64.getDecoder();
byte[] sessionKeyBytes = decoder.decode(sessionKey);
byte[] ivBytes = decoder.decode(iv);
byte[] encryptedBytes = decoder.decode(encryptedData);
// JDK does not support PKCS7Padding, use PKCS5Padding instead
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec skeySpec = new SecretKeySpec(sessionKeyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
byte[] ret = cipher.doFinal(encryptedBytes);
String result = new String(ret);
logger.info("抖音解密手机号结果:" + result);
if (!result.contains("phoneNumber")) {
logger.info("抖音解密手机号失败");
return "false";
}
return JsonUtils.getValueByPath(result, "phoneNumber");
} catch (Exception e) {
logger.error("抖音解密手机号异常", e);
return "false";
}
}
/**
* 获取无需用户授权的接口调用凭证client_token
*
* @return
*/
public String getClientToken() {
try {
logger.info("开始获取抖音小程序的client_token");
String activeProfile = applicationContext.getEnvironment().getActiveProfiles()[0];
String url = SANDBOX_CLIENT_TOKEN_URL;
if (!StringUtils.equals("dev", activeProfile)) {
url = PROD_CLIENT_TOKEN_URL;
}
Map<String, Object> param = new HashMap<>();
param.put("client_key", appid);
param.put("client_secret", appSecret);
param.put("grant_type", "client_credential");
String result = OkHttpUtil.builder().url(url)
.addHeader("Content-Type", "multipart/form-data").addParams(param)
.post(true).sync();
logger.info("获取抖音小程序的client_token结果:" + result);
if (!result.contains("access_token")) {
logger.info("获取抖音小程序的client_token失败");
return null;
}
return JsonUtils.getValueByPath(result, "data/access_token");
} catch (Exception e) {
logger.error("获取抖音小程序的client_token异常", e);
return null;
}
}
/**
* 获取二维码
*
* @param clientToken
* @param page
* @param scene
* @return
*/
public String getAcode(String clientToken, String page, String scene) {
try {
logger.info("开始获取抖音小程序的二维码");
// 请求头
Map<String, String> headers = new HashMap<>();
headers.put("content-type", "application/json");
headers.put("access-token", clientToken);
// 参数
Map<String, Object> param = new HashMap<>();
param.put("app_name", "douyin");
param.put("appid", appid);
String path = URLEncoder.encode(page + "?" + scene, "UTF-8");
param.put("path", path);
param.put("set_icon", true);
// 发送请求
String result = OkHttpUtil.builder().url(GET_ACODE_URL)
.addHeaders(headers).addParams(param)
.post(true).sync();
logger.info("获取抖音小程序二维码的结果:" + result);
if (!result.contains("img")) {
logger.info("获取抖音小程序的二维码失败");
return null;
}
return JsonUtils.getValueByPath(result, "data/img");
} catch (Exception e) {
logger.info("获取抖音小程序的二维码异常", e);
return null;
}
}
/**
* 获取链接
*
* @param pageUrl
* @return
*/
public String getLink(String clientToken, String pageUrl) {
try {
logger.info("开始获取抖音小程序的链接");
// 请求头
Map<String, String> headers = new HashMap<>();
headers.put("content-type", "application/json");
headers.put("access-token", clientToken);
// 参数
Map<String, Object> param = new HashMap<>();
param.put("app_name", "douyin");
param.put("appid", appid);
String[] page = pageUrl.split("\\?");
param.put("path", page[0]);
// 包装query
String[] query = page[1].split("=");
Map<String, Object> queryMap = new HashMap<>();
queryMap.put(query[0], Integer.parseInt(query[1]));
param.put("query", JSON.toJSONString(queryMap));
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 7);
param.put("expire_time", calendar.getTimeInMillis());
// 发送请求
String result = OkHttpUtil.builder().url(GET_LINK_URL)
.addHeaders(headers).addParams(param)
.post(true).sync();
logger.info("获取抖音小程序链接的结果:" + result);
if (!result.contains("url_link")) {
logger.info("获取抖音小程序的链接失败");
return null;
}
return JsonUtils.getValueByPath(result, "data/url_link");
} catch (Exception e) {
logger.error("获取抖音小程序的链接异常", e);
return null;
}
}
}
package com.wwdz.ch.wx.manager; package com.wwdz.ch.wx.manager;
import cn.binarywang.wx.miniapp.api.WxMaService; import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
...@@ -18,15 +17,24 @@ import java.io.InputStream; ...@@ -18,15 +17,24 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/**
* 微信小程序服务
*/
@Service @Service
public class WxLoginManager { public class WxLoginManager {
private static final Logger logger = LoggerFactory.getLogger(WxMaServiceImpl.class); private static final Logger logger = LoggerFactory.getLogger(WxLoginManager.class);
// 微信小程序appid
private static final String appid = "wx5b4409448bf2c72b"; private static final String appid = "wx5b4409448bf2c72b";
// 微信小程序secret
private static final String secret = "6fee0d7b2197845fed0a3fe8f5a9bd66"; private static final String secret = "6fee0d7b2197845fed0a3fe8f5a9bd66";
// 微信小程序获取access_token地址
private static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; private static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
// 微信小程序获取用户手机号地址
private static final String GET_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s"; private static final String GET_PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";
// 微信小程序获取小程序码地址
private static final String GET_WXACODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"; private static final String GET_WXACODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
// 微信小程序获取短链接地址
private static final String GET_LINK_URL = "https://api.weixin.qq.com/wxa/genwxashortlink?access_token=%s"; private static final String GET_LINK_URL = "https://api.weixin.qq.com/wxa/genwxashortlink?access_token=%s";
@Autowired @Autowired
...@@ -66,7 +74,7 @@ public class WxLoginManager { ...@@ -66,7 +74,7 @@ public class WxLoginManager {
return "sessionFalse"; return "sessionFalse";
} }
if (StringUtils.isBlank(sessionKey)) { if (StringUtils.isBlank(sessionKey)) {
logger.error("微信登录,调用官方接口失败:{}", dto.getCode()); logger.info("微信登录,调用官方接口失败:{}", dto.getCode());
return "sessionFalse"; return "sessionFalse";
} }
...@@ -117,7 +125,7 @@ public class WxLoginManager { ...@@ -117,7 +125,7 @@ public class WxLoginManager {
} }
} }
public String getLink (String pageUrl) { public String getLink(String pageUrl) {
try { try {
String accessToken = getAccessToken(); String accessToken = getAccessToken();
String url = String.format(GET_LINK_URL, accessToken); String url = String.format(GET_LINK_URL, accessToken);
......
...@@ -81,6 +81,16 @@ public interface ItemService { ...@@ -81,6 +81,16 @@ public interface ItemService {
*/ */
Result getWxacode(String page, String scene, HttpServletResponse response); Result getWxacode(String page, String scene, HttpServletResponse response);
/**
* 获取小程序码
*
* @param page
* @param scene
* @param response
* @return
*/
Result getAcode(String page, String scene, Integer loginType, HttpServletResponse response);
/** /**
* 获取微信小程序短链接 * 获取微信小程序短链接
* *
...@@ -89,6 +99,14 @@ public interface ItemService { ...@@ -89,6 +99,14 @@ public interface ItemService {
*/ */
Result getWxLink(String pageUrl); Result getWxLink(String pageUrl);
/**
* 获取小程序链接
*
* @param pageUrl
* @return
*/
Result getLink(String pageUrl, Integer loginType);
/** /**
* 上传图片 * 上传图片
* *
......
...@@ -7,30 +7,39 @@ import javax.servlet.http.HttpServletRequest; ...@@ -7,30 +7,39 @@ import javax.servlet.http.HttpServletRequest;
public interface UserService { public interface UserService {
/** /**
* 微信登录 * 发送手机验证码
*
* @param dto
* @return
*/
Result regCaptcha(UserRequestDto dto);
/**
* 手机号登录
* *
* @param dto * @param dto
* @param request * @param request
* @return * @return
*/ */
Result loginByWx(UserRequestDto dto, HttpServletRequest request); Result loginByMobile(UserRequestDto dto, HttpServletRequest request);
/** /**
* 发送手机验证码 * 快捷登录
* *
* @param dto * @param dto
* @param request
* @return * @return
*/ */
Result regCaptcha(UserRequestDto dto); Result login(UserRequestDto dto, HttpServletRequest request);
/** /**
* 手机号登录 * 微信登录
* *
* @param dto * @param dto
* @param request * @param request
* @return * @return
*/ */
Result loginByMobile(UserRequestDto dto, HttpServletRequest request); Result loginByWx(UserRequestDto dto, HttpServletRequest request);
/** /**
* 修改个性签名 * 修改个性签名
......
...@@ -137,15 +137,46 @@ public class WxItemController { ...@@ -137,15 +137,46 @@ public class WxItemController {
@ApiOperation(value = "小程序码") @ApiOperation(value = "小程序码")
@GetMapping("/getWxacode") @GetMapping("/getWxacode")
public Result getWxacode(String page, String scene, HttpServletResponse response) { public Result getWxacode(String page, String scene, HttpServletResponse response) {
logger.info("【请求开始】获取微信小程序码,请求参数:{}", "page=" + page +",scene=" + scene);
return itemService.getWxacode(page, scene, response); return itemService.getWxacode(page, scene, response);
} }
@ApiOperation(value = "小程序码")
@GetMapping("/getAcode")
public Result getAcode(String page, String scene, Integer loginType, HttpServletResponse response) {
logger.info("【请求开始】获小程序码,请求参数:{}", "page=" + page + ",scene=" + scene + ",loginType=" + loginType);
if (StringUtils.isBlank(page)) {
return Result.failed("页面路径不能为空");
}
if (StringUtils.isBlank(scene)) {
return Result.failed("路径参数不能为空");
}
if (Objects.isNull(loginType)) {
return Result.failed("请提供请求的环境类型");
}
return itemService.getAcode(page, scene, loginType, response);
}
@ApiOperation(value = "小程序链接") @ApiOperation(value = "小程序链接")
@PostMapping("/getWxLink") @PostMapping("/getWxLink")
public Result getWxLink(@RequestBody ItemRequestDto dto) { public Result getWxLink(@RequestBody ItemRequestDto dto) {
logger.info("【请求开始】获取小程序链接,请求参数:{}", JSON.toJSONString(dto));
return itemService.getWxLink(dto.getPageUrl()); return itemService.getWxLink(dto.getPageUrl());
} }
@ApiOperation(value = "小程序链接")
@PostMapping("/getLink")
public Result getLink(@RequestBody ItemRequestDto dto) {
logger.info("【请求开始】获取小程序链接,请求参数:{}", JSON.toJSONString(dto));
if (StringUtils.isBlank(dto.getPageUrl())) {
return Result.failed("页面路径不能为空");
}
if (Objects.isNull(dto.getLoginType())) {
return Result.failed("请提供请求的环境类型");
}
return itemService.getLink(dto.getPageUrl(), dto.getLoginType());
}
@ApiOperation("图片上传") @ApiOperation("图片上传")
@PostMapping(value ="/uploadImage") @PostMapping(value ="/uploadImage")
public Result uploadImage(@RequestParam("image") MultipartFile file) { public Result uploadImage(@RequestParam("image") MultipartFile file) {
......
...@@ -4,6 +4,7 @@ package com.wwdz.ch.wx.web; ...@@ -4,6 +4,7 @@ package com.wwdz.ch.wx.web;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.wwdz.ch.core.type.Result; import com.wwdz.ch.core.type.Result;
import com.wwdz.ch.wx.constant.CacheCodeConstants; import com.wwdz.ch.wx.constant.CacheCodeConstants;
import com.wwdz.ch.wx.constant.LoginTypeEnum;
import com.wwdz.ch.wx.entity.request.UserRequestDto; import com.wwdz.ch.wx.entity.request.UserRequestDto;
import com.wwdz.ch.wx.service.UserService; import com.wwdz.ch.wx.service.UserService;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
...@@ -32,6 +33,39 @@ public class WxUserController { ...@@ -32,6 +33,39 @@ public class WxUserController {
private UserService userService; private UserService userService;
@ApiOperation(value = "快捷登录")
@PostMapping("/login")
public Result login(@RequestBody UserRequestDto dto, HttpServletRequest request) {
logger.info("【请求开始】快捷登录,请求参数:{}", JSON.toJSONString(dto));
if (Objects.isNull(dto.getLoginType())) {
return Result.failed("请提供快捷登录的方式");
}
if (dto.getLoginType().equals(LoginTypeEnum.WECHAT.getCode())) {
if (StringUtils.isBlank(dto.getCode())) {
return Result.failed("授权码不能为空");
}
if (Objects.isNull(dto.getType())) {
return Result.failed("版本类型不能为空");
}
if (dto.getType() == 2) {
if (StringUtils.isBlank(dto.getEncryptedData()) || StringUtils.isBlank(dto.getIv())) {
return Result.failed("encryptedData或iv不能为空");
}
}
}
if (dto.getLoginType().equals(LoginTypeEnum.ALIPAY.getCode())) {
if (StringUtils.isBlank(dto.getEncryptedData())) {
return Result.failed("encryptedData不能为空");
}
}
if (dto.getLoginType().equals(LoginTypeEnum.TIKTOK.getCode())) {
if (StringUtils.isBlank(dto.getEncryptedData()) || StringUtils.isBlank(dto.getIv())) {
return Result.failed("encryptedData或iv不能为空");
}
}
return userService.login(dto, request);
}
@ApiOperation(value = "微信登录") @ApiOperation(value = "微信登录")
@PostMapping("/loginByWx") @PostMapping("/loginByWx")
public Result loginByWx(@RequestBody UserRequestDto dto, HttpServletRequest request) { public Result loginByWx(@RequestBody UserRequestDto dto, HttpServletRequest request) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment