ソースを参照

微信H5核身认证

zoujiajian 2 年 前
コミット
b746b77ddd

+ 6 - 0
netflix-common/pom.xml

@@ -98,6 +98,12 @@
             <artifactId>tencentcloud-sdk-java-sms</artifactId>
             <version>3.1.694</version>
         </dependency>
+
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java-faceid</artifactId>
+            <version>3.1.694</version>
+        </dependency>
     </dependencies>
 
 

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/UserCertRecordMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.UserCertRecord;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserCertRecordMapper
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:11
+ */
+public interface UserCertRecordMapper extends BaseMapper<UserCertRecord> {
+}

+ 28 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/UserCertRecord.java

@@ -0,0 +1,28 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserCert
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:00
+ */
+@Getter
+@Setter
+public class UserCertRecord extends BaseEntity{
+	private Long userId;
+
+	private String name;
+
+	private String sex;
+
+	private String ident;
+
+	private String front;
+
+	private String reverse;
+
+	private String addr;
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/request/UserIndentCertReq.java

@@ -0,0 +1,20 @@
+package com.cyksj.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserIndentCertReq
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 11:17
+ */
+@Getter
+@Setter
+public class UserIndentCertReq {
+	private Long userId;
+
+	private String bindState;
+
+	private String redirectUrl;
+}

+ 24 - 0
netflix-dao/src/main/java/com/cyksj/model/response/WxCertAuthTokenResp.java

@@ -0,0 +1,24 @@
+package com.cyksj.model.response;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserCertAuthTokenResp
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:16
+ */
+@Getter
+@Setter
+public class WxCertAuthTokenResp {
+	/**
+	 * 用于发起核身流程的URL,仅微信H5场景使用
+	 */
+	private String Url;
+
+	/**
+	 * 一次核身流程的标识
+	 */
+	private String BizToken;
+}

+ 3 - 1
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -666,7 +666,9 @@ public class RedisService {
         CORP_CUSTOMER_ACQUISTION_UNIONID_CLICKID("corp:customer:unionId:%s","unionid 对应的clickId",60*60*24),
 
         WEEKEND_DUTY_UNDERSTAFFED_NOTIFY("weekend_duty_understaffed_notify","周末值班人员不足短信通知key",60*60),
-        DOUBLE_VERIFY_CODE_VIEW_MINUTES_KEY("double_verify_code_view_minutes_key","双重验证码查看同时间段人数限制",60)
+        DOUBLE_VERIFY_CODE_VIEW_MINUTES_KEY("double_verify_code_view_minutes_key","双重验证码查看同时间段人数限制",60),
+
+        WX_INDENT_BIND_KEY("wx_indent_bind:key:", "微信身份授权绑定key", 60 * 60 * 24),
         ;
 
         private String name;

+ 20 - 0
netflix-service/src/main/java/com/cyksj/service/user/UserIdentCertService.java

@@ -0,0 +1,20 @@
+package com.cyksj.service.user;
+
+import com.cyksj.model.request.UserIndentCertReq;
+import com.cyksj.model.response.WxCertAuthTokenResp;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserIdentCertService
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:21
+ */
+public interface UserIdentCertService {
+	WxCertAuthTokenResp wxH5IndentCert(UserIndentCertReq indentCertReq) throws Exception;
+
+	Boolean wxH5IndentCertResult(Long userId, String bizToken) throws Exception;
+
+	String bindWxUser(long userId);
+
+	Boolean checkCertRecord(long userId);
+}

+ 157 - 0
netflix-service/src/main/java/com/cyksj/service/user/impl/UserIdentCertServiceImpl.java

@@ -0,0 +1,157 @@
+package com.cyksj.service.user.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.mapper.UserCertRecordMapper;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.model.entity.User;
+import com.cyksj.model.entity.UserCertRecord;
+import com.cyksj.model.request.UserBindInfoReq;
+import com.cyksj.model.request.UserIndentCertReq;
+import com.cyksj.model.response.WxCertAuthTokenResp;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.market.task.BindTaskService;
+import com.cyksj.service.user.UserBindRelationService;
+import com.cyksj.service.user.UserIdentCertService;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.faceid.v20180301.FaceidClient;
+import com.tencentcloudapi.faceid.v20180301.models.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserIdentCertServiceImpl
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:21
+ */
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserIdentCertServiceImpl implements UserIdentCertService {
+	private final UserBindRelationService userBindRelationService;
+
+	private final UserCertRecordMapper userCertRecordMapper;
+
+	private final BindTaskService bindTaskService;
+
+	private final UserMapper userMapper;
+
+	private final RedisService redisService;
+
+	private static final String TENCENT_SECRET_ID = "AKIDBB3jEqR0Y95zpfTix1vd6fMqAIahc4Ka";
+
+	private static final String TENCENT_SECRET_KEY = "c6YtNm63rcQ1QdiGmEbmEPSTPF3e4KQK";
+
+	private static final String ruleId = "1";
+
+	@Override
+	public Boolean checkCertRecord(long userId) {
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		Integer count = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class)
+				.in(UserCertRecord::getUserId, userIdList));
+		return count > 0 ? true : false;
+	}
+
+	@Override
+	public String bindWxUser(long userId) {
+		User user = userMapper.selectById(userId);
+		if (StrUtil.isNotBlank(user.getOpenId())) {
+			return null;
+		}
+		String state = StringUtil.randomString(6);
+		redisService.set(RedisService.key.WX_INDENT_BIND_KEY.getEnvName() + state, userId, RedisService.key.WX_INDENT_BIND_KEY.getTimeout());
+		return state;
+	}
+
+	@Override
+	public WxCertAuthTokenResp wxH5IndentCert(UserIndentCertReq indentCertReq) throws Exception {
+		Long userId = indentCertReq.getUserId();
+		String redirectUrl = indentCertReq.getRedirectUrl();
+		List<Long> userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+		String bindState = indentCertReq.getBindState();
+		if (userIdList.size() == 1 && StrUtil.isNotEmpty(bindState)) {
+			User user = userMapper.selectById(userId);
+			//绑定微信端用户
+			if (StrUtil.isEmpty(user.getOpenId())) {
+				UserBindInfoReq request = new UserBindInfoReq();
+				request.setType(StrUtil.isNotBlank(user.getLoginPhone()) ? 1 : 2);
+				request.setUserId(userId);
+				bindTaskService.bindOtherAccount(request);
+				userIdList = userBindRelationService.getRelationUserIdList(userId, null);
+			}
+		}
+
+		Integer count = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class)
+				.in(UserCertRecord::getUserId, userIdList));
+		if (count > 0) throw BusinessRuntimeException.getInstance("您已完成认证了..");
+
+		Credential cred = new Credential(TENCENT_SECRET_ID, TENCENT_SECRET_KEY);
+		// 实例化一个http选项,可选的,没有特殊需求可以跳过
+		HttpProfile httpProfile = new HttpProfile();
+		httpProfile.setEndpoint("faceid.tencentcloudapi.com");
+		// 实例化一个client选项,可选的,没有特殊需求可以跳过
+		ClientProfile clientProfile = new ClientProfile();
+		clientProfile.setHttpProfile(httpProfile);
+		// 实例化要请求产品的client对象,clientProfile是可选的
+		FaceidClient client = new FaceidClient(cred, "", clientProfile);
+		// 实例化一个请求对象,每个接口都会对应一个request对象
+		DetectAuthRequest req = new DetectAuthRequest();
+		req.setRuleId(ruleId);
+		req.setRedirectUrl(redirectUrl);
+		// 返回的resp是一个DetectAuthResponse的实例,与请求对象对应
+		DetectAuthResponse resp = client.DetectAuth(req);
+
+		log.info("微信h5核身认证,返回:{}", Jsons.toJson(resp));
+
+		WxCertAuthTokenResp tokenResp = new WxCertAuthTokenResp();
+		BeanUtil.copyProperties(resp, tokenResp);
+		return tokenResp;
+	}
+
+	@Override
+	public Boolean wxH5IndentCertResult(Long userId, String bizToken) throws Exception {
+		Credential cred = new Credential(TENCENT_SECRET_ID, TENCENT_SECRET_KEY);
+		// 实例化一个http选项,可选的,没有特殊需求可以跳过
+		HttpProfile httpProfile = new HttpProfile();
+		httpProfile.setEndpoint("faceid.tencentcloudapi.com");
+		// 实例化一个client选项,可选的,没有特殊需求可以跳过
+		ClientProfile clientProfile = new ClientProfile();
+		clientProfile.setHttpProfile(httpProfile);
+		// 实例化要请求产品的client对象,clientProfile是可选的
+		FaceidClient client = new FaceidClient(cred, "", clientProfile);
+		// 实例化一个请求对象,每个接口都会对应一个request对象
+		GetDetectInfoEnhancedRequest req = new GetDetectInfoEnhancedRequest();
+		req.setBizToken(bizToken);
+		req.setRuleId(ruleId);
+		// 返回的resp是一个GetDetectInfoEnhancedResponse的实例,与请求对象对应
+		GetDetectInfoEnhancedResponse resp = client.GetDetectInfoEnhanced(req);
+		DetectInfoText text = resp.getText();
+		Boolean flag = false;
+		if (text.getErrCode() == 0) {
+			UserCertRecord certRecord = new UserCertRecord();
+			String ocrIdCard = text.getOcrIdCard();
+			Integer count = userCertRecordMapper.selectCount(Wrappers.lambdaQuery(UserCertRecord.class)
+					.eq(UserCertRecord::getIdent, ocrIdCard));
+			if (count == 0) {
+				flag = true;
+				certRecord.setIdent(text.getOcrIdCard());
+				certRecord.setName(text.getOcrName());
+				certRecord.setSex(text.getOcrGender());
+				certRecord.setUserId(userId);
+				certRecord.setAddr(text.getOcrAddress());
+				userCertRecordMapper.insert(certRecord);
+			}
+		}
+		return flag;
+	}
+}

+ 2 - 0
netflix-service/src/main/java/com/cyksj/service/user/impl/UserServiceImpl.java

@@ -117,6 +117,8 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
 
 	private final UserDistributeSharedMapper userDistributeSharedMapper;
 
+	private final UserCertRecordMapper userCertRecordMapper;
+
 	private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance();
 
 	@Override

+ 0 - 1
netflix-web/src/main/java/com/cyksj/web/controller/user/DistributePopularizeController.java

@@ -135,7 +135,6 @@ public class DistributePopularizeController {
 		}
 		DistributePopularizeView distributePopularizeView = new DistributePopularizeView();
 		String dsUrl = String.format(envCommonService.DISTRIBUTE_DEFAULT_URL_PREFIX, user.getShowId());
-//		distributePopularizeView.setUrl(String.format("https://%s/8081/api/auth/weChat?url=https://%s/yinhe/web&sharedId=%s", domain, domain, userId));
 		distributePopularizeView.setUrl(dsUrl);
 		distributePopularizeView.setUrlCode(QrCodeUtil.generateAsBase64(distributePopularizeView.getUrl(), QrConfig.create(), "png"));
 		distributePopularizeView.setGotPoints(user.getPoints());

+ 67 - 0
netflix-web/src/main/java/com/cyksj/web/controller/user/UserCertController.java

@@ -0,0 +1,67 @@
+package com.cyksj.web.controller.user;
+
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.model.request.UserIndentCertReq;
+import com.cyksj.model.response.WxCertAuthTokenResp;
+import com.cyksj.service.user.UserIdentCertService;
+import com.cyksj.web.util.StpUserUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 项目名: yhlxj2
+ * 文件名: UserCertController
+ * 创建者: JavaZou
+ * 创建时间:2024/2/21 10:13
+ */
+@RequestMapping("/applets/user/cert")
+@RestController
+@RequiredArgsConstructor
+public class UserCertController {
+
+	private final UserIdentCertService userIdentCertService;
+
+
+	/**
+	 * 用户是否已授权认证
+	 */
+	@GetMapping("/check/record")
+	public Result<Boolean> checkCertRecord() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		Boolean flag = userIdentCertService.checkCertRecord(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(flag);
+	}
+
+	/**
+	 * 非微信端 用户身份认证 建立微信用户绑定关系
+	 */
+	@PostMapping("/bind")
+	public Result<String> bindWxUser() {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		String state = userIdentCertService.bindWxUser(userId);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(state);
+	}
+
+
+	/**
+	 * 用户微信H5认证
+	 */
+	@PostMapping("/auth")
+	public Result<WxCertAuthTokenResp> wxH5IndentCertAuth(@RequestBody UserIndentCertReq indentCertReq) throws Exception {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		indentCertReq.setUserId(userId);
+		WxCertAuthTokenResp resp = userIdentCertService.wxH5IndentCert(indentCertReq);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(resp);
+	}
+
+	/**
+	 * 用户微信H5认证结果查询
+	 */
+	@PostMapping("/auth/result/{token}")
+	public Result<Boolean> wxH5IndentCertAuthResult(@PathVariable String token) throws Exception {
+		long userId = StpUserUtil.getLoginIdAsLong();
+		Boolean flag = userIdentCertService.wxH5IndentCertResult(userId, token);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(flag);
+	}
+}