unionId和openId的区别
微信开发过程中,经常会遇到,一个企业有多个小程序和公众号,在不同的小程序和公众号中,会有不同的openid。如果想要确定是同一个人,就需要用到unionid机制。
-
在小程序中,openID是小程序的普通用户的一个唯一的标识,只针对当前的小程序有效。公众号同理。
-
同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。
看博主的文章中,获取openId的方式就可以获取到unionId,只是我们没用到而已。
微信除了返回openid之外,还会有access_token和refresh_token,我们的token是前端和我们后端来进行交互的,微信返回的这两个token是我们与微信来交互的。
微信官方提供的登录方案,总结为三步:(就是我们下面的那个流程,图也一模一样)
- 前端通过 wx.login() 获取一次性加密凭证 code,交给后端。
- 后端把这个 code 传输给微信服务器端,换取用户唯一标识 openId 和授权凭证 session_key。(用于后续服务器端和微信服务器的特殊 API 调用,具体看:微信官方文档-服务端获取开放数据)。
- 后端把从微信服务器获取到的用户凭证与自行生成的登录态凭证(token),传输给前端。前端保存起来,下次请求的时候带给后端,就能识别哪个用户。
【微信小程序】token 无感刷新
token
- 作用:在访问一些接口时,需要传入token,就是它。
有效期:2小时(安全)。
refresh_token
- 作用: 当token的有效期过了之后,可以使用它去请求一个特殊接口(这个接口也是后端指定的,明确需要传入refresh_token),并返回一个新的token回来(有效期还是2小时),以替换过期的那个token。
有效期:14天。(最理想的情况下,一次登陆可以持续14天。)
安全还是体验
- 从安全角度来看 token 必须要具有一定的时效性,失效后的 token 不再能标识用是登录状态。
- 另外也要考虑用户的体验,例如用户在 token 失效的前 1 分钟打开小程序,用户浏览小程序 1 分钟后 token 失效,用户不得不再次去登录,这样的用户体验是极差的。
- 为了既能保证安全性又兼顾用户体验,咱们需要能够自动刷新 token 的方法,即 refresh_token。
refresh_token工作机制
- 用户在首次完成登录时会分别得到 token 和 refresh_token
- 当 token 失效后(例如2小时之后),调用接口A会返回 401 状态码(这是与后端约定好的规则)
- 检测状态码是否为 401,如果是,则携带refreshToken去调用刷新token的接口
- 刷新 token 的接口后会返回新的 token 和 refreshToken
- 把401的接口A重新发送一遍
注意:
refresh_token也是有过期时间的,只不过一般会比token过期时间更长一些。这就是为啥如果某个应用我们天天打开,则不会提示我们登录,如果是有几周或更长时间去打开时,会再次要求我们登录。
refresh_token一个更常见的名字叫token无感刷新。
下面的才是正文,上面的是面试官问到的问题,总结一下,等有时间再回来整合
乘客登录
需求说明
- openid是小程序端微信的唯一标识
数据库表
表中存在openid就不是第一次登录,否则就是第一次登录
登录流程时序
- 如果是第一次登录,注册之后也是要返回token的
- code就是单纯什么参数都没有,直接调用微信接口服务的wx.login()获取即可
在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同。
- localStorage的优势
1、localStorage拓展了cookie的4K限制
2、localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽,但是这个却是只有在高版本的浏览器中才支持的
- localStorage的局限
1、浏览器的大小不统一,并且在IE8以上的IE版本才支持localStorage这个属性
2、目前所有的浏览器中都会把localStorage的值类型限定为string类型,这个在对我们日常比较常见的JSON对象类型需要一些转换
3、localStorage在浏览器的隐私模式下面是不可读取的
4、localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
5、localStorage不能被爬虫抓取到
- localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空
乘客登录具体实现
根据code获取openid
- 远程调用的是service模块中的controller
获取token
获取登录用户信息
- 获取openid的时候我们就创建了用户到数据库中,就是获取的这个用户信息数据,没什么难度
- @RequestHeader和HttpServletRequest都可以获取请求头,效果都是一样的,用哪个都行
- 这里还用到了BeanUtils.copy()来进行实体类的复制
这个功能很简单,就是对数据库的一个简单查询,就不贴代码了
登录校验 使用自定义注解和aop !!!
- 只有Controller中才能直接获取请求头,在这里我们使用RequestContextHolder
获取乘客手机号码
// 实体类中只有用户id和code两个字段
@Operation(summary = "更新客户微信手机号码")
@PostMapping("/updateWxPhoneNumber")
public Result<Boolean> updateWxPhoneNumber(@RequestBody UpdateWxPhoneForm updateWxPhoneForm) {
return Result.ok(customerInfoService.updateWxPhoneNumber(updateWxPhoneForm));
}
更新客户微信手机号码
@Override
public Boolean updateWxPhoneNumber(UpdateWxPhoneForm updateWxPhoneForm) {
//1 根据code值获取微信绑定手机号码
// 这儿的code就还是那个随机的登录的那个code
try {
WxMaPhoneNumberInfo phoneNoInfo =
wxMaService.getUserService().getPhoneNoInfo(updateWxPhoneForm.getCode());
String phoneNumber = phoneNoInfo.getPhoneNumber();
//更新用户信息
Long customerId = updateWxPhoneForm.getCustomerId();
CustomerInfo customerInfo = customerInfoMapper.selectById(customerId);
customerInfo.setPhone(phoneNumber);
customerInfoMapper.updateById(customerInfo);
return true;
} catch (WxErrorException e) {
throw new GuiguException(ResultCodeEnum.DATA_ERROR);
}
}
司机登录
司机端微信小程序登录
<dependencies>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
</dependency>
</dependencies>
- 复制微信工具配置类,与乘客端一样
- 而且登录流程也是和乘客基本一样的
右边的还有第六步,返回司机id
@Tag(name = "司机API接口管理")
@RestController
@RequestMapping(value="/driver/info")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class DriverInfoController {
@Autowired
private DriverInfoService driverInfoService;
@Operation(summary = "小程序授权登录")
@GetMapping("/login/{code}")
public Result<Long> login(@PathVariable String code) {
return Result.ok(driverInfoService.login(code));
}
}
@Slf4j
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class DriverInfoServiceImpl extends ServiceImpl<DriverInfoMapper, DriverInfo> implements DriverInfoService {
@Autowired
private WxMaService wxMaService;
@Autowired
private DriverInfoMapper driverInfoMapper;
@Autowired
private DriverSetMapper driverSetMapper;
@Autowired
private DriverAccountMapper driverAccountMapper;
@Autowired
private DriverLoginLogMapper driverLoginLogMapper;
//小程序授权登录
@Override
public Long login(String code) {
try {
//根据code + 小程序id + 秘钥请求微信接口,返回openid
// 其中 小程序id + 秘钥 在微信配置类中已经被注入了
WxMaJscode2SessionResult sessionInfo =
wxMaService.getUserService().getSessionInfo(code);
String openid = sessionInfo.getOpenid();
//根据openid查询是否第一次登录
LambdaQueryWrapper<DriverInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DriverInfo::getWxOpenId,openid);
DriverInfo driverInfo = driverInfoMapper.selectOne(wrapper);
if(driverInfo == null) {
//添加司机基本信息
driverInfo = new DriverInfo();
driverInfo.setNickname(String.valueOf(System.currentTimeMillis()));
driverInfo.setAvatarUrl("https://oss.aliyuncs.com/aliyun_id_photo_bucket/default_handsome.jpg");
driverInfo.setWxOpenId(openid);
driverInfoMapper.insert(driverInfo);
//初始化司机设置
DriverSet driverSet = new DriverSet();
driverSet.setDriverId(driverInfo.getId());
driverSet.setOrderDistance(new BigDecimal(0));//0:无限制
driverSet.setAcceptDistance(new BigDecimal(SystemConstant.ACCEPT_DISTANCE));//默认接单范围:5公里
driverSet.setIsAutoAccept(0);//0:否 1:是
driverSetMapper.insert(driverSet);
//初始化司机账户信息
DriverAccount driverAccount = new DriverAccount();
driverAccount.setDriverId(driverInfo.getId());
driverAccountMapper.insert(driverAccount);
}
//记录司机登录信息
DriverLoginLog driverLoginLog = new DriverLoginLog();
driverLoginLog.setDriverId(driverInfo.getId());
driverLoginLog.setMsg("小程序登录");
driverLoginLogMapper.insert(driverLoginLog);
//返回司机id
return driverInfo.getId();
} catch (WxErrorException e) {
throw new GuiguException(ResultCodeEnum.DATA_ERROR);
}
}
}
@FeignClient(value = "service-driver")
public interface DriverInfoFeignClient {
/** * 小程序授权登录 * @param code * @return */
@GetMapping("/driver/info/login/{code}")
Result<Long> login(@PathVariable("code") String code);
}
@Slf4j
@Tag(name = "司机API接口管理")
@RestController
@RequestMapping(value="/driver")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class DriverController {
@Autowired
private DriverService driverService;
@Operation(summary = "小程序授权登录")
@GetMapping("/login/{code}")
public Result<String> login(@PathVariable String code) {
return Result.ok(driverService.login(code));
}
}
@Slf4j
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class DriverServiceImpl implements DriverService {
@Autowired
private DriverInfoFeignClient driverInfoFeignClient;
@Autowired
private RedisTemplate redisTemplate;
//登录
@Override
public String login(String code) {
//远程调用,得到司机id
Result<Long> longResult = driverInfoFeignClient.login(code);
//TODO 判断
Long driverId = longResult.getData();
//token字符串
String token = UUID.randomUUID().toString().replaceAll("-","");
//放到redis,设置过期时间
redisTemplate.opsForValue().set(RedisConstant.USER_LOGIN_KEY_PREFIX + token,
driverId.toString(),
RedisConstant.USER_LOGIN_KEY_TIMEOUT,
TimeUnit.SECONDS);
return token;
}
}
获取登录司机信息
- 是否需要创建腾讯云人脸模型,这里只返回布尔值,并不是在这里进行人脸识别,所以这个函数实际上也就是调用数据库查询数据,在这里就不做具体的描述
开通腾讯云对象存储COS
接下来我们要实现司机认证模块,司机认证模块需要集成腾讯云对象存储COS、腾讯云OCR证件识别及腾讯云人脸模型库创建
,先学习完这些前置接口,再编写认证提交接口,如图:
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
- 我们项目基于腾讯云对象存储服务COS,存储司机认证相关资料(
身份证、驾驶证
) - 要使用腾讯云对象存储服务,首先进行开通,注册腾讯云之后,开通就可以了
- 使用对象存储服务,可以在控制台里面进行操作,也可以使用Java代码进行操作,这些操作,腾讯云官方提供详细文档说明,按照文档就方便进行操作
腾讯云对象存储开通
很简单,微信登录实名认证,然后直接使用就可以了。
- 创建存储桶,访问权限改为公共读写,只是为了学习方便,工作中肯定不能这么用。存储地域(ap-beijing),代码中需要用到。
- 如果使用java代码,获取当前腾讯云账户id和key。
主账号=》访问管理=》访问密钥=》API密钥管理=》新建密钥并记录在本地
@Tag(name = "腾讯云cos上传接口管理")
@RestController
@RequestMapping(value="/cos")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class CosController {
@Autowired
private CosService cosService;
//文件上传接口
@Operation(summary = "上传")
//@GuiguLogin
@PostMapping("/upload")
public Result<CosUploadVo> upload(@RequestPart("file") MultipartFile file,
@RequestParam(name = "path",defaultValue = "auth") String path) {
CosUploadVo cosUploadVo = cosService.uploadFile(file,path);
return Result.ok(cosUploadVo);
}
}
@Slf4j
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class CosServiceImpl implements CosService {
@Autowired
private CosFeignClient cosFeignClient;
//文件上传接口
@Override
public CosUploadVo uploadFile(MultipartFile file, String path) {
//远程调用
Result<CosUploadVo> cosUploadVoResult = cosFeignClient.upload(file,path);
CosUploadVo cosUploadVo = cosUploadVoResult.getData();
return cosUploadVo;
}
}
@FeignClient(value = "service-driver")
public interface CosFeignClient {
//文件上传
@PostMapping(value = "/cos/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<CosUploadVo> upload(@RequestPart("file") MultipartFile file, @RequestParam("path") String path);
}
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
</dependency>
@Data
@Component
@ConfigurationProperties(prefix = "tencent.cloud")
public class TencentCloudProperties {
private String secretId;
private String secretKey;
private String region;
private String bucketPrivate;
}
@Slf4j
@Tag(name = "腾讯云cos上传接口管理")
@RestController
@RequestMapping(value="/cos")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class CosController {
@Autowired
private CosService cosService;
@Operation(summary = "上传")
@PostMapping("/upload")
public Result<CosUploadVo> upload(@RequestPart("file") MultipartFile file,
@RequestParam("path") String path) {
CosUploadVo cosUploadVo = cosService.upload(file,path);
return Result.ok(cosUploadVo);
}
}
@Slf4j
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class CosServiceImpl implements CosService {
@Autowired
private TencentCloudProperties tencentCloudProperties;
@Override
public CosUploadVo upload(MultipartFile file, String path) {
// 1 初始化用户身份信息(secretId, secretKey)。
String secretId = tencentCloudProperties.getSecretId();
String secretKey = tencentCloudProperties.getSecretKey();
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
// 2 设置 bucket 的地域, COS 地域
Region region = new Region(tencentCloudProperties.getRegion());
ClientConfig clientConfig = new ClientConfig(region);
// 这里建议设置使用 https 协议
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成 cos 客户端。
COSClient cosClient = new COSClient(cred, clientConfig);
//文件上传
//元数据信息
ObjectMetadata meta = new ObjectMetadata();
meta.setContentLength(file.getSize());
meta.setContentEncoding("UTF-8");
meta.setContentType(file.getContentType());
//向存储桶中保存文件
String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); //文件后缀名
String uploadPath = "/driver/" + path + "/" + UUID.randomUUID().toString().replaceAll("-", "") + fileType;
// 01.jpg
// /driver/auth/0o98754.jpg
PutObjectRequest putObjectRequest = null;
try {
//1 bucket名称
//2
putObjectRequest = new PutObjectRequest(tencentCloudProperties.getBucketPrivate(),
uploadPath,
file.getInputStream(),
meta);
} catch (IOException e) {
throw new RuntimeException(e);
}
putObjectRequest.setStorageClass(StorageClass.Standard);
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); //上传文件
cosClient.shutdown();
//返回vo对象
CosUploadVo cosUploadVo = new CosUploadVo();
cosUploadVo.setUrl(uploadPath);
//TODO 图片临时访问url,回显使用
cosUploadVo.setShowUrl("");
return cosUploadVo;
}
}
- @RequestPart 和 @RequestParam都可以接收MultipartFile ,没有区别
- public static final String MULTIPART_FORM_DATA_VALUE = “multipart/form-data”,代表以文件格式进行传输
获取临时签名URL
我们的存储桶设置成私有读写
,此时我们需要一个图片的回显地址,这个地址是可以设置过期时间的。
//获取临时签名URL
@Override
public String getImageUrl(String path) {
if(!StringUtils.hasText(path)) return "";
//获取cosclient对象
COSClient cosClient = this.getCosClient();
//GeneratePresignedUrlRequest
GeneratePresignedUrlRequest request =
new GeneratePresignedUrlRequest(tencentCloudProperties.getBucketPrivate(),
path, HttpMethodName.GET);
//设置临时URL有效期为15分钟
Date date = new DateTime().plusMinutes(15).toDate();
request.setExpiration(date);
//调用方法获取
URL url = cosClient.generatePresignedUrl(request);
cosClient.shutdown();
return url.toString();
}
腾讯云身份证识别接口
司机注册成功之后,应该引导他去做实名认证,这就需要用到腾讯云身份证识别和云存储功能了
身份证识别API地址:https://cloud.tencent.com/document/product/866/33524
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>${
tencentcloud.version}</version>
</dependency>
@Tag(name = "腾讯云识别接口管理")
@RestController
@RequestMapping(value="/ocr")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class OcrController {
@Autowired
private OcrService ocrService;
@Operation(summary = "身份证识别")
@PostMapping("/idCardOcr")
public Result<IdCardOcrVo> idCardOcr(@RequestPart("file") MultipartFile file) {
IdCardOcrVo idCardOcrVo = ocrService.idCardOcr(file);
return Result.ok(idCardOcrVo);
}
}
@Slf4j
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class OcrServiceImpl implements OcrService {
@Autowired
private TencentCloudProperties tencentCloudProperties;
@Autowired
private CosService cosService;
//身份证识别
@Override
public IdCardOcrVo idCardOcr(MultipartFile file) {
try{
//图片转换base64格式字符串
byte[] base64 = Base64.encodeBase64(file.getBytes());
String fileBase64 = new String(base64);
// 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密
Credential cred = new Credential(tencentCloudProperties.getSecretId(),
tencentCloudProperties.getSecretKey());
// 实例化一个http选项,可选的,没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ocr.tencentcloudapi.com");
// 实例化一个client选项,可选的,没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
OcrClient client = new OcrClient(cred,tencentCloudProperties.getRegion(), clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
IDCardOCRRequest req = new IDCardOCRRequest();
//设置文件
req.setImageBase64(fileBase64);
// 返回的resp是一个IDCardOCRResponse的实例,与请求对象对应
IDCardOCRResponse resp = client.IDCardOCR(req);
//转换为IdCardOcrVo对象
IdCardOcrVo idCardOcrVo = new IdCardOcrVo();
if (StringUtils.hasText(resp.getName())) {
//身份证正面
idCardOcrVo.setName(resp.getName());
idCardOcrVo.setGender("男".equals(resp.getSex()) ? "1" : "2");
idCardOcrVo.setBirthday(DateTimeFormat.forPattern("yyyy/MM/dd").parseDateTime(resp.getBirth()).toDate());
idCardOcrVo.setIdcardNo(resp.getIdNum());
idCardOcrVo.setIdcardAddress(resp.getAddress());
//上传身份证正面图片到腾讯云cos
CosUploadVo cosUploadVo = cosService.upload(file, "idCard");
idCardOcrVo.setIdcardFrontUrl(cosUploadVo.getUrl());
idCardOcrVo.setIdcardFrontShowUrl(cosUploadVo.getShowUrl());
} else {
//身份证反面
//证件有效期:"2010.07.21-2020.07.21"
String idcardExpireString = resp.getValidDate().split("-")[1];
idCardOcrVo.setIdcardExpire(DateTimeFormat.forPattern("yyyy.MM.dd").parseDateTime(idcardExpireString).toDate());
//上传身份证反面图片到腾讯云cos
CosUploadVo cosUploadVo = cosService.upload(file, "idCard");
idCardOcrVo.setIdcardBackUrl(cosUploadVo.getUrl());
idCardOcrVo.setIdcardBackShowUrl(cosUploadVo.getShowUrl());
}
return idCardOcrVo;
} catch (Exception e) {
throw new GuiguException(ResultCodeEnum.DATA_ERROR);
}
}
}
@FeignClient(value = "service-driver")
public interface OcrFeignClient {
/** * 身份证识别 * @param file * @return */
@PostMapping(value = "/ocr/idCardOcr", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
Result<IdCardOcrVo> idCardOcr(@RequestPart("file") MultipartFile file);
}
@Tag(name = "腾讯云识别接口管理")
@RestController
@RequestMapping(value="/ocr")
@SuppressWarnings({
"unchecked", "rawtypes"})
public class OcrController {
@Autowired
private OcrService ocrService;
@Operation(summary = "身份证识别")
@GuiguLogin
@PostMapping("/idCardOcr")
public Result<IdCardOcrVo> uploadDriverLicenseOcr(@RequestPart("file") MultipartFile file) {
return Result.ok(ocrService.idCardOcr(file));
}
}
@Service
@SuppressWarnings({
"unchecked", "rawtypes"})
public class OcrServiceImpl implements OcrService {
@Autowired
private OcrFeignClient ocrFeignClient;
//身份证识别
@Override
public IdCardOcrVo idCardOcr(MultipartFile file) {
Result<IdCardOcrVo> ocrVoResult = ocrFeignClient.idCardOcr(file);
IdCardOcrVo idCardOcrVo = ocrVoResult.getData();
return idCardOcrVo;
}
}
腾讯云行驶证识别接口
流程与身份证识别一致,不赘述
获取司机的认证信息
- 司机进行操作首先进行登录,登录成功之后,进行认证,跳转到认证页面完成认证
- 查看认证信息,进入到认证页面时候,回显证件信息
实际上就是查询数据库中的信息,我们在认证的时候插入的数据,不赘述。
修改司机认证信息
认证状态:
0:未认证 【刚注册完为未认证状态】
1:审核中 【提交了认证信息后变为审核中】
2:认证通过 【后台审核通过】
-1:认证未通过【后台审核不通过】
- 第一次登录时候,完成用户注册,注册时候,当前认证状态值是0(未认证)
- 上传认证信息(填写认证资料)之后,进行提交,提交之后,当前认证状态值1(审核中)
- 司机端提交审核资料之后,后台管理员对提交资料进行审核,审核通过,认证状态值2,审核没有通过,认证状态值-1
司机开启接单的条件:
1、登录
2、认证通过
3、建立了腾讯云人员库人员
4、当日验证了人脸识别
开通人脸识别
新注册的司机进行人脸信息采集,类似于在公司里面进行人脸录入,每天进行人脸打卡
官网地址:https://cloud.tencent.com/product/facerecognition
-
创建人员库
人脸识别=》人员库管理=》人员管理 -
这儿的人脸识别不是那种活体检测,就是一张自己的照片,我们自己公司的客服进行审核。
-
身份证和驾驶证必须真实,是腾讯云进行审核,手持和人脸是我们后台审核的。
-
腾讯云人脸识别后会返回一个
人脸模型id
,细节是同一张图片只能生成一次,如果没有返回,说明照片重复了 -
审核有个状态码
部分内容转载自:
https://blog.csdn.net/weixin_44649793/article/details/137612245
https://juejin.cn/post/7300592516759306291
https://blog.csdn.net/2301_76855186/article/details/131213259
我们还是要把科学和技术分开,如果一讲做事要有目的性,目的性就是技术,不是科学。科学就是你的兴趣爱好,为了搞清楚不惜一切代价。所以,科学家大多数看上去都是“疯子”,很少科学家能看到自己的研究在人类社会的成就。比如,麦克斯韦不知道他的方程对人类社会这么重要,现在的无线世界是基于他的电磁场理论;法拉第也不知道现在的电气化社会是源自他的线圈框实验;毕达哥拉斯也想不到他的几何学理论演变成了微积分的萌芽……。
https://baijiahao.baidu.com/s?id=1760664270073856317&wfr=spider&for=pc
擦亮花火、共创未来——任正非在“难题揭榜”花火奖座谈会上的讲话
任正非
文章评论