| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- package com.izouma.nineth.service;
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONObject;
- import com.alibaba.fastjson.serializer.SerializerFeature;
- import com.aliyun.oss.common.utils.HttpUtil;
- import com.aliyuncs.utils.HttpsUtils;
- import com.github.kevinsawicki.http.HttpRequest;
- import com.izouma.nineth.annotations.RedisLock;
- import com.izouma.nineth.domain.IdentityAuth;
- import com.izouma.nineth.domain.User;
- import com.izouma.nineth.dto.PageQuery;
- import com.izouma.nineth.enums.AuthStatus;
- import com.izouma.nineth.exception.BusinessException;
- import com.izouma.nineth.repo.IdentityAuthRepo;
- import com.izouma.nineth.repo.UserRepo;
- import com.izouma.nineth.utils.DateTimeUtils;
- import com.izouma.nineth.utils.HttpUtils;
- import com.izouma.nineth.utils.JpaUtils;
- import lombok.AllArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.http.HttpResponse;
- import org.apache.http.util.EntityUtils;
- import org.springframework.core.env.Environment;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.PageRequest;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Service;
- import java.time.LocalDate;
- import java.time.temporal.ChronoUnit;
- import java.util.*;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.atomic.AtomicInteger;
- import java.util.regex.Pattern;
- import java.util.stream.Collectors;
- @Service
- @AllArgsConstructor
- @Slf4j
- public class IdentityAuthService {
- private IdentityAuthRepo identityAuthRepo;
- private UserRepo userRepo;
- private UserService userService;
- private AdapayService adapayService;
- private RedisTemplate<String, Object> redisTemplate;
- private Environment env;
- private SysConfigService sysConfigService;
- private CacheService cacheService;
- public Page<IdentityAuth> all(PageQuery pageQuery) {
- return identityAuthRepo
- .findAll(JpaUtils.toSpecification(pageQuery, IdentityAuth.class), JpaUtils.toPageRequest(pageQuery));
- }
- public void apply(IdentityAuth identityAuth) {
- if (identityAuth.getUserId() == null) {
- throw new BusinessException("用户不存在");
- }
- User user = userRepo.findByIdAndDelFalse(identityAuth.getUserId()).orElseThrow(new BusinessException("用户不存在"));
- List<IdentityAuth> auths = identityAuthRepo.findByUserIdAndDelFalse(identityAuth.getUserId());
- auths.stream().filter(auth -> auth.getStatus() == AuthStatus.PENDING).findAny().ifPresent(a -> {
- throw new BusinessException("正在审核中,请勿重复提交");
- });
- auths.stream().filter(auth -> auth.getStatus() == AuthStatus.SUCCESS).findAny().ifPresent(a -> {
- throw new BusinessException("已认证,请勿重复提交");
- });
- identityAuth.setStatus(AuthStatus.PENDING);
- identityAuthRepo.save(identityAuth);
- user.setAuthStatus(AuthStatus.PENDING);
- userService.save(user);
- cacheService.clearUserMy(user.getId());
- identityAuthRepo.deleteDuplicated(identityAuth.getUserId(), identityAuth.getId());
- }
- public void audit(Long id, AuthStatus status, String reason) {
- IdentityAuth auth = identityAuthRepo.findByIdAndDelFalse(id).orElseThrow(new BusinessException("申请不存在"));
- if (auth.getStatus() != AuthStatus.PENDING) {
- throw new BusinessException("已经审核过");
- }
- User user = userRepo.findByIdAndDelFalse(auth.getUserId()).orElseThrow(new BusinessException("用户不存在"));
- if (user.getAuthStatus() != AuthStatus.SUCCESS) {
- if (status == AuthStatus.SUCCESS) {
- user.setAuthId(auth.getId());
- }
- user.setAuthStatus(status);
- userService.save(user);
- }
- auth.setStatus(status);
- auth.setReason(reason);
- auth.setAutoValidated(true);
- identityAuthRepo.save(auth);
- cacheService.clearUserMy(user.getId());
- identityAuthRepo.deleteDuplicated(auth.getUserId(), auth.getId());
- }
- public List<User> repeat(String idNo, Long userId) {
- List<IdentityAuth> auths = identityAuthRepo.findAllByIdNoAndUserIdIsNotAndDelFalse(idNo, userId);
- if (auths.isEmpty()) {
- return null;
- }
- List<Long> userIds = auths.stream().map(IdentityAuth::getUserId).distinct().collect(Collectors.toList());
- return userRepo.findByIdInAndDelFalse(userIds);
- }
- // public void validate(String name, String phone, String idno) {
- // String body = HttpRequest.post("https://jubrige.market.alicloudapi.com/mobile/3-validate-transfer")
- // .header("Authorization", "APPCODE b48bc8f6759345a79ae20a951f03dabe")
- // .contentType(HttpRequest.CONTENT_TYPE_FORM)
- // .form("idCardNo", idno)
- // .form("mobile", phone)
- // .form("name", name)
- // .body();
- // JSONObject jsonObject = JSONObject.parseObject(body);
- // if (jsonObject.getInteger("code") != 200) {
- // String msg = jsonObject.getString("msg");
- // throw new BusinessException(msg);
- // } else {
- // JSONObject data = jsonObject.getJSONObject("data");
- // int result = data.getIntValue("result");
- // String desc = data.getString("desc");
- // if (result != 0) {
- // throw new BusinessException(desc);
- // } else {
- // log.info("{} {} {} 实名认证通过", name, phone, idno);
- // }
- // }
- // }
- public void validateV2(String name, String phone, String idno) {
- String host = "https://mobilecert.market.alicloudapi.com";
- String path = "/mobile3MetaSimple";
- String method = "GET";
- String appcode = "af29c2d37c4f415fac930d82f01fb559";
- Map<String, String> headers = new HashMap<String, String>();
- //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
- headers.put("Authorization", "APPCODE " + appcode);
- Map<String, String> querys = new HashMap<String, String>();
- querys.put("identifyNum", idno);
- querys.put("mobile", phone);
- querys.put("userName", name);
- try {
- /**
- * 重要提示如下:
- * HttpUtils请从
- * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
- * 下载
- *
- * 相应的依赖请参照
- * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
- */
- HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
- System.out.println(response.toString());
- //获取response的body
- JSONObject jsonObject = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
- log.info("validate {} {} \n{}", name, idno, JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat));
- if (jsonObject.getInteger("code") != 200) {
- String msg = jsonObject.getString("message");
- throw new BusinessException(msg);
- } else {
- JSONObject data = jsonObject.getJSONObject("data");
- Integer bizCode = Optional.ofNullable(data.getInteger("bizCode")).orElse(3);
- if (bizCode != 1) {
- throw new BusinessException("不匹配");
- } else {
- log.info("{} {} {} 实名认证通过", name, phone, idno);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public void validate(String name, String phone, String idno) {
- String body = HttpRequest.get("https://mobilecert.market.alicloudapi.com/mobile3MetaSimple")
- .header("Authorization", "APPCODE af29c2d37c4f415fac930d82f01fb559")
- .contentType("text/html; charset=utf-8")
- .form("identifyNum", idno)
- .form("userName", name)
- .form("mobile", phone)
- .body();
- JSONObject jsonObject = JSONObject.parseObject(body);
- log.info("validate {} {} \n{}", name, idno, JSON.toJSONString(jsonObject, SerializerFeature.PrettyFormat));
- if (jsonObject.getInteger("code") != 200) {
- String msg = jsonObject.getString("message");
- throw new BusinessException(msg);
- } else {
- JSONObject data = jsonObject.getJSONObject("data");
- Integer bizCode = Optional.ofNullable(data.getInteger("bizCode")).orElse(3);
- if (bizCode != 1) {
- throw new BusinessException("不匹配");
- } else {
- log.info("{} {} {} 实名认证通过", name, phone, idno);
- }
- }
- }
- public void removeDuplicated() {
- boolean hasMore = true;
- int pageNum = 0;
- AtomicInteger count = new AtomicInteger();
- while (hasMore) {
- Page<Long> page = identityAuthRepo.listUserId(PageRequest.of(pageNum, 100));
- List<Long> userIds = page.getContent();
- userIds.forEach(userId -> {
- userRepo.findById(userId).ifPresent(user -> {
- log.info("removeDuplicated {}/{} ", count.incrementAndGet(), page.getTotalElements());
- List<IdentityAuth> list = identityAuthRepo.findByUserId(userId);
- if (list.size() > 1) {
- IdentityAuth auth = list.stream()
- .filter(i -> i.getStatus() == AuthStatus.SUCCESS)
- .findAny().orElse(null);
- if (auth != null) {
- userRepo.setAuthStatus(user.getId(), auth.getStatus(), auth.getId());
- int num = identityAuthRepo.deleteDuplicated(user.getId(), auth.getId());
- log.info("deleted {}", num);
- return;
- }
- auth = list.stream()
- .filter(i -> i.getStatus() == AuthStatus.PENDING)
- .findAny().orElse(null);
- if (auth != null) {
- userRepo.setAuthStatus(user.getId(), auth.getStatus(), auth.getId());
- int num = identityAuthRepo.deleteDuplicated(user.getId(), auth.getId());
- log.info("deleted {}", num);
- return;
- }
- auth = list.stream()
- .filter(i -> i.getStatus() == AuthStatus.FAIL)
- .findAny().orElse(null);
- if (auth != null) {
- userRepo.setAuthStatus(user.getId(), auth.getStatus(), auth.getId());
- int num = identityAuthRepo.deleteDuplicated(user.getId(), auth.getId());
- log.info("deleted {}", num);
- return;
- }
- } else if (list.size() == 1) {
- userRepo.setAuthStatus(user.getId(), list.get(0).getStatus(), list.get(0).getId());
- }
- });
- });
- hasMore = page.hasNext();
- pageNum++;
- }
- }
- @Scheduled(fixedRate = 60000)
- @RedisLock(value = "autoValidate", expire = 30, unit = TimeUnit.MINUTES)
- public void autoValidate() {
- if (!sysConfigService.getBoolean("auto_validate")) return;
- log.info("autoValidate");
- if (Arrays.asList(env.getActiveProfiles()).contains("dev")) {
- return;
- }
- try {
- List<IdentityAuth> list = identityAuthRepo.findByStatusAndAutoValidated(AuthStatus.PENDING, false);
- list.parallelStream().forEach(identityAuth -> {
- Map<String, Object> map = auth(identityAuth);
- audit(identityAuth.getId(), (AuthStatus) map.get("status"), (String) map.get("reason"));
- });
- } catch (Exception e) {
- log.error("批量自动实名出错", e);
- }
- }
- public Map<String, Object> auth(IdentityAuth identityAuth) {
- log.info("实名 {}", identityAuth.getRealName());
- Map<String, Object> result = new HashMap<>();
- String reason = null;
- User user = userRepo.findById(identityAuth.getUserId()).orElseThrow(new BusinessException("用户不存在"));
- if (user.getAuthStatus() == AuthStatus.SUCCESS) {
- result.put("status", AuthStatus.SUCCESS);
- } else if (!Pattern
- .matches("[1-9]{1}[0-9]{5}(19|20)[0-9]{2}((0[1-9]{1})|(1[0-2]{1}))((0[1-9]{1})|([1-2]{1}[0-9]{1}|(3[0-1]{1})))[0-9]{3}[0-9x]{1}", identityAuth
- .getIdNo()
- .toLowerCase())) {
- result.put("status", AuthStatus.FAIL);
- result.put("reason", "身份证格式错误");
- } else {
- LocalDate birth = DateTimeUtils.toLocalDate(identityAuth.getIdNo().substring(6, 14), "yyyyMMdd");
- long age = ChronoUnit.YEARS.between(birth, LocalDate.now());
- if (age < 18) {
- result.put("status", AuthStatus.FAIL);
- result.put("reason", "未满18岁");
- } else if (age > 60) {
- result.put("status", AuthStatus.FAIL);
- result.put("reason", "超过60岁");
- } else {
- int count = identityAuthRepo.countByIdNoAndStatus(identityAuth.getIdNo(), AuthStatus.SUCCESS);
- if (count >= 3) {
- result.put("status", AuthStatus.PENDING);
- result.put("reason", "同一身份证注册超过3个");
- } else {
- try {
- validateV2(identityAuth.getRealName(), identityAuth.getPhone(), identityAuth.getIdNo());
- result.put("status", AuthStatus.SUCCESS);
- } catch (Exception e) {
- log.error("自动实名出错", e);
- if ("不匹配".equals(e.getMessage())) {
- result.put("status", AuthStatus.FAIL);
- } else {
- result.put("status", AuthStatus.PENDING);
- }
- result.put("reason", e.getMessage());
- }
- }
- }
- }
- return result;
- }
- }
|