想知道微信怎么做指纹支付开发?看这里!

2023-11-14

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

作者简介:Henryye,叶轩,来自腾讯微信事业群,主要负责腾讯开源项目TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter )生物认证平台的开发、维护与运营。

提到指纹支付,你会怎么做?

假如有一天,产品经理安排你做指纹支付,并且要下版本就上,你会怎么做?

如果是产品大哥,就从工位下面抽出一把指甲刀架在他脖子上,让他跪在墙角唱征服;

如果是产品妹子,就让她请你喝咖啡,然后谈天说地,趁此机会告诉她“还是选择世界和平吧,比做指纹支付简单多了。”

当然,想象还是太温柔了。真正做过指纹支付项目的在下,经常会在半夜三更回忆起当年做指纹支付需求时候的噩梦,在梦里,我就给自己加戏,手撕产品经理。

也许产品大大们会发出抗议:“指纹支付而已,客户端现成的接口,有何难?”

系统接口行不行?

从2013年iPhone 5s第一款带有指纹识别功能的iPhone上市以来,“指纹支付”这个词就开始频繁出现在各个产品的PM列表排期中。但是,Android 6.0以前的设备,并没有一个统一的指纹认证接口。这也就意味着如果你是一个苦逼的程序猿,那么你就要一家家适配各自的指纹方案,并且还要维护厂商的接口升级。如果结合Android市场的碎片化来看,想要全机型覆盖,简直就是Impossible Mission。实际上,在项目初期,微信便尝试了一家家接入,结果仅仅接入华为Mate 7和荣耀7,便用了整整三个月!这种投入显然是得不偿失的。

好在,从Android 6.0开始,系统提供了标准的FingerprintManager。这一重大利好,让做着类似需求的程序猿们仿佛在黑暗中看到一丝光明,因为这个接口看上去是那么简单易用。无论你是什么品牌的手机,只要是Android 6.0或更新的系统,按照下面的写法,就可以实现指纹认证功能:

FingeprintManager mFingeprintManager = ...
mFingeprintManager.authenticate(null, 
mCancellationSignal, 0 , new AuthenticationCallback(){...},
 null);
设计本身也很简单:

系统认证接口

看上去很完美,仿佛实现指纹支付根本不用开发1个版本,只用1小时,对不对!

但是仔细看下这个接口,感觉哪里不太对:接口仅仅返回认证成功/失败,如果直接信任这个结果,手机被root了,岂不是随时可以将认证结果从false改为true?

那我们换一种思路:root的手机不让用指纹支付行不行?

傻孩子,那你怎么判断手机是不是root呢?不也是通过Android接口获取的值么?这个值一样可以被改掉。

支付安全不可儿戏,一旦出问题,就是重大事故。所幸的是,Google也意识到了这个问题,所以在发布指纹认证接口的同时,增强了原本的KeyStore接口,和Fingeprprint接口联动(代码实现可参考Google官方Sample,链接:https://github.com/googlesamples/android-FingerprintDialog):

这张图看上去不明觉厉,原理其实并不难:Google在Android 6.0之后,允许用户在应用中生成一对非对称密钥,将私钥存储在TEE中(什么是TEE?稍后会讲),任何人,包括应用自己甚至Android系统都无法获取私钥,除非用户使用指纹授权才能使用,签名或者加密传入的数据,然后输出密文。这样的话,就可以利用密钥的签名-验签机制(小白不懂什么是签名验签?Google下咯~或者看这篇文章解释签名的部分),只有用户使用指纹签名之后,才能产生正确的签名,后台验签即可,这样就能保证链路安全。

这个设计非常巧妙,但是Google百密一疏:如果黑客在密钥生成的时候就拦截了请求,替换为自己的密钥,那么后面签名和加密,用的也是黑客的密钥,那么整套系统的设计也就崩塌了。

Hack示意

另外还有一个问题,如果仅仅返回true/false,那么只要是录入到设备内的指纹,就可以假冒你的身份支付。这对于家里有熊孩子的家长来说,简直就是银行卡噩梦。雪上加霜的是,对于Android设备而言(其实iOS也是一样),只要知道了锁屏密码就可以录入新的指纹。如果支付后台直接信任指纹认证结果,就相当于将原本非常秘密的支付密码,退化到了锁屏密码的级别。这样,无论支付后台做了多么严密的风控策略,按照木桶原理,从根本上整个系统就是不符合支付安全的。

当然,当时也有类似于FIDO(链接:https://fidoalliance.org/)之类的认证联盟,但是整个流程过于复杂,甚至还要求在应用后台植入sdk。而且,类似方案的中心服务权限过高,会导致如支付笔数、开通用户数等关键指标为人所知,因此也就无法使用。并且支持设备数实在太少,也并无接入动力。

研究过这些之后,发现并不可直接使用任何一个方案,场面一度尴尬。没有合适的轮子,怎么办?

没有轮子,能造轮子么?

让我们回头看看Android系统的指纹接口设计:

  • 方便的指纹接口,完美!
  • 创造性得将指纹模块与密钥模块结合起来,使得用户授权即签名变得可能,完美!

那Google没有做到什么呢?

  • 由于没有一个可信的信任根,导致密钥很容易被替换;
  • 无法从认证结果中获取到底是哪一个用户授权本次认证请求;

同时,我们意识到,在生物认证领域这个千亿级市场中,缺乏一个统一、安全、易接入的认证标准,微信有这样的需求,其他应用也必然如此。微信有能力解决这些问题,实现自己的业务需求,也希望将成功经验复制。既然这样,借此机会制定一个生物认证标准,提供一个生物认证平台,微信责无旁贷,这就是SOTER的起源。

如果以做标准的要求来实现SOTER,那么除了刚刚所述的系统接口缺陷之外,系统设计时还需要考虑:

  • 后台不存储任何敏感信息,包括对称密钥、非对称密钥私钥,更不能将用户生态无特征(如指纹图案)以任何形式传输或存储,防止应用后台被脱库;
  • 如果有后台交互,不暴露应用方核心商业隐私,如认证次数、业务开通次数;
  • 应用接入门槛低,客户端无须集成重量级sdk,后台无须集成sdk;
  • 简单易用,第三方应用只需要操作上层接口,无须进行复杂的底层开发。

如何产生一个可信的信任根(设备根密钥)?

信任根的重要性之前已经说明。如果一个系统依赖密钥签名,有一个可以信任的根密钥,才有可能构建安全的信任模型。但是,如果一台手机出厂之后才产生根密钥(ATTK),那么中间有足够时间窗口给到黑产从业者替换掉它。因此,常规方式产生根密钥一定是不行的。所以,我们有了一个大胆的想法:直接与厂商合作,在设备出厂之前,产线上生成设备根密钥,公钥通过厂商服务传输给微信密钥服务——TAM。这个想法虽然对厂商改造比较大,但是由于我们直接通产业链上游(高通、MTK等)合作,研发出了一套统一的解决方案,以及产线工具,成功说服厂商对产线做了最小化的改造。It’s tough, but we did it!

设备根密钥流程

  1. 厂商在产线上对设备下发生成设备根密钥命令;
  2. TEE中生成一对设备唯一的RSA-2048非对称密钥,私钥存储在设备RPMB区域,没有任何厂商或者应用方可以读取(包括微信与设备厂商),公钥以及设备ID导出;
  3. 公钥和设备ID上传到厂商服务器,之后通过公众平台安全接口,传输到微信公众平台;
  4. 微信公众平台将公钥与设备ID传输到微信TAM服务器。

这里,我们又遇到了我们的老朋友:TEE(Trusted Execution Environment),后面我们也会多次与这个名词打交道。如果想要看详细的介绍,可以参考这里(链接:https://en.wikipedia.org/wiki/Trusted_execution_environment)。当然了,我相信大部分同学都跟我一样,只想要一个形象的解释。简单地说,你的手机中,除了类似Android这样的操作系统之外,还有一个独立的环境。这个环境目前并无行之有效的破解方法,也就是说即使Root了Android系统,都无法破解TEE中的数据。如果将整部手机比作房子的话,Android操作环境就是客厅,TEE就是你的保险箱。可想而知,如果将所有的数据都存储在TEE,关键操作也在TEE内进行,岂不美哉!当然了,这样的话,所有从TEE中出来的敏感数据,就一定要添加上使用可信密钥对其的签名了。

有了设备根密钥之后,认证链的构造逻辑就清晰了很多:采用密钥链的形式,用已认证的密钥来认证未认证的密钥就可以了!

如何构造完整认证流程?

方法论有了,实施就变得简单。

但是,依然有一个问题需要思考:到底需要多少层密钥呢?密钥层数少,那么每一次都需要前往中心服务(微信TAM)验签,对第三方应用而言,会更担心泄露自己的商业逻辑;密钥层数越多,会增加了传输复杂度和失败率。经过多方讨论,SOTER决定使用三级密钥,除了产线预制的设备根密钥之外,增加定义应用密钥(每一个应用生命周期内只需要存在一对)和业务密钥(每一个业务需要一对)。事实证明,这是一个明智的选择:这样既保证了流程的流畅度,又保证应用的关键商业隐私不暴露。为什么?往下看。

架构

SOTER架构图

我们十分欣赏Google的指纹和密钥模块接口设计,因此,我们与厂商合作,在此基础上添加patch包,即可迅速实现整个上层架构。

准备应用密钥(ASK)

准备应用密钥流程示意图

  1. 应用第一次启动时,或者在第一次使用业务之前,请求生成设备根密钥;
  2. 密钥生成之后,私钥在被TEE保护,加密存储;
  3. 公钥和设备ID等相关信息,在TEE内直接被设备密钥私钥签名之后,返回给应用;
  4. 应用将公钥相关信息和签名传输至应用后台;
  5. 应用后台通过微信公众平台后台接口,请求验签;
  6. TAM使用对应的设备密钥公钥验签,通过之后返回给应用;
  7. 应用后台存储对应的应用公钥。

传输给后台的原串示例:

注1:自设备出厂即在TEE中存储。每一次SOTER相关操作都会使该值自增,后台存储该放重放因子。如果后台发现本次请求防重放因子比已记录的值小,则可认为是非法请求。

注2:本意为类Unix系统中用户ID,在Android系统中,一般而言每一个应用都有一个uid,可用于区分应用以及权限控制。注意,uid不同,对应的应用密钥与业务密钥均不同,后台应将uid与cpu_id一起区分密钥。

准备业务密钥(Auth Key)

准备业务密钥流程示意图

  1. 应用在开通业务时(如指纹支付),请求生成业务密钥。同时,在生成时声明该密钥除非用户指纹授权,否则私钥不可使用。
  2. 密钥生成之后,私钥在被TEE保护,加密存储;
  3. 公钥和设备ID等相关信息,在TEE内直接被应用密钥私钥签名之后,返回给应用;
  4. 应用将公钥相关信息和签名传输至应用后台;
  5. 应用后台使用对应的应用密钥公钥验签,无须请求微信TAM中心服务;
  6. 验签成功之后,应用后台存储对应的业务密钥。

传输数据与含义与应用密钥相同,不再赘述。

认证流程

认证流程示意图

  1. 客户端请求后台,获取挑战因子;
  2. 获取挑战因子之后,将挑战因子送往TEE,准备签名结构体,准备签名;
  3. 应用请求用户指纹授权;
  4. 用户指纹授权后,直接将本次认证使用指纹在本设备内的索引传输给密钥模块,在TEE内使用业务密钥私钥签名挑战因子以及该索引。

应用获取原串与签名串后,传输至应用后台。应用后台使用对应的业务密钥公钥验签,如果成功,则此次认证或者开通请求合法。

传输给后台原串示例

流程是否符合要求?

轮子造好了,我们在自我欣赏的路上越走越远。回过头来看,SOTER是否满足了我们的要求呢?

  • 添加信任根:SOTER在工厂环境中传输设备根密钥,保证信任根安全;
  • 可区分指纹:认证之后,TEE内部直接传输本次使用的指纹ID,可使应用自由选择是否区分指纹;
  • 后台不存储敏感信息:后台仅存储设备ID和公钥,从此即使后台设计再烂,也不再害怕脱库;
  • 后台交互不暴露隐私:独创应用密钥,保证业务开通、业务使用量等不需要经过应用服务器;
  • 后台不需要sdk:后台使用成熟的公众平台接口,文档丰富,学习成本低,更无须sdk。

当然了,我们的方案得到了各大厂商、芯片上的认可,在短时间内,已经拥有了数亿设备的支持,覆盖几乎所有的主流手机品牌,因此应用接入完全无须考虑是否需要多设备适配,或者质疑适配不足。顺便,我们支持了vivo和OPPO的5.x指纹机型,即使系统本身不具有统一的指纹接口。

然而,还有最后两点没有做到:

  • 客户端接入门槛低,客户端sdk轻量,甚至不需要sdk;
  • 简单易用,客户端无须进行深度开发即可使用。

解决这两个问题的方法只有:开源!

我们开源了什么?

为了满足不同应用的不同场景,我们开源了:

  • SOTER客户端核心接口soter-core:SOTER内部操作密钥、调用指纹的直接接口。sdk大小约40KB,对安装包大小增量可忽略不计;
  • SOTER客户端过程封装接口soter-wrapper:封装了SOTER具体流程以及适配问题机型。sdk大小约70KB,安装包大小增量更少;
  • 快速上手的客户端demo,从零开始,帮你短短几行代码实现指纹支付;
  • 完整的客户端文档和后台接口文档;
  • 完整的原理剖析和快速入手。

这一切,尽在TENCENT SOTER(GitHub地址:https://github.com/Tencent/soter,点击 阅读全文 亦可直接访问)。

使用SOTER最快能多块?如果你只需要做锁屏之类对安全性要求不高的需求,只需要:

  • 添加gradle依赖

在项目的build.gradle中,添加 SOTER依赖

dependencies {    
        ...    
        compile 'com.tencent.soter:soter-wrapper:1.3.8'    
        ... 
}
  • 声明权限

在 AndroidManifest.xml中添加使用指纹权限

<uses-permission 
android:name="android.permission.USE_FINGERPRINT"/>
  • 初始化

初始化过程整个应用声明周期内只需要进行一次,用于生成基本配置和检查设备支持情况。你可以选择在Application的onCreate()中,或者在使用SOTER之前进行初始化。

InitializeParam param = new InitializeParam.InitializeParamBuilder()
.setScenes(0) // 场景值常量,后续使用该常量进行密钥生成或指纹认证
.build();
SoterWrapperApi.init(context, new 
SoterProcessCallback<SoterProcessNoExtResult>() {...}, 
param);
  • 准备密钥

需要在使用指纹认证之前生成相关密钥

SoterWrapperApi.prepareAuthKey(new
 SoterProcessCallback<SoterProcessKeyPreparationResult
>() {...},false, true, 0, null, null);
  • 进行指纹认证

密钥生成完毕之后,可以使用封装接口调用指纹传感器进行认证。

AuthenticationParam param = new AuthenticationParam.AuthenticationParamBuilder()
  .setScene(0)                                    
  .setContext(MainActivity.this)                                    
  .setFingerprintCanceller(mSoterFingerprintCanceller)
  .setPrefilledChallenge("test challenge")    
                                
  .setSoterFingerprintStateCallback(new 
SoterFingerprintStateCallback() {...}).build();
SoterWrapperApi.requestAuthorizeAndSign(new
SoterProcessCallback<SoterProcessAuthenticationResult>
() {...}, param);

当然了,如果你想要实现指纹支付、指纹登录等高安全性场景,还有一些其他工作要做,具体可以参考我们的示例代码(链接:https://github.com/Tencent/soter/tree/master/soter-client-demo)和安全接入文档(链接:https://github.com/Tencent/soter/wiki/%E5%AE%89%E5%85%A8%E6%8E%A5%E5%85%A5)。

SOTER(GitHub地址:https://github.com/Tencent/soter) 开源之后,已经有包括微众银行在内的多个应用已经接入,这些应用接入的时间均不超过一个版本。使用的场景也从指纹支付,到指纹登录、指纹解锁。用过的,都说好。

那么,让我们再回顾下开头的场景:“我们要做指纹支付,下个版本上…”,想必你已经知道怎么做了,括弧逃~


问答

为什么手机屏下指纹技术难以实现?

相关阅读

操作系统指纹识别概述

移动支付安全评测:微信支付篇

微信送你一把未来的万能钥匙


此文已由作者授权腾讯云+社区发布,转载请注明文章出处

原文链接:https://cloud.tencent.com/developer/article/1031094?fromSource=waitui

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

想知道微信怎么做指纹支付开发?看这里! 的相关文章

  • 在 Android 中将应用程序上下文保存到静态变量是否安全?

    我知道在 Android 上使用静态变量是相当危险的 特别是当您将它们引用到活动时 但是 如果我有一个扩展 Application 的类 我们称此类为 App 引用此类的实例是否安全 如果是这样 任何其他类对应用程序上下文进行任何类型的引用
  • iPad 3 中配备 Xcode 4.2 和 Retina 的 iOS 5.1

    我有一台装有 Mac OS X Snow Leopard 的 Mac 我可以添加 iOS 5 1 吗 使用 iPad 3 的新分辨率 我们将如何处理图像 因为如果该应用程序将在 iPhone 3GS 4 和 iPad 3 中运行 我认为我们
  • Locale.getDefault().getCountry() 返回空字符串

    我正在尝试使用国家 地区代码获取用户语言 例如en US es es 但是当我使用Locale getDefault getCountry 它返回空字符串 虽然它给了我正确的语言Locale getDefault getLanguage N
  • 在 Swift 中检查一个数组是否包含另一个数组的所有元素

    我想为数组编写一个扩展来检查一个数组是否包含另一个数组的所有元素 在我的用例中它是字符串对象 但我一直得到 Cannot convert value of type T Generator Element to expected argum
  • invalidateOptionsMenu 在片段中不起作用

    显示或隐藏项目ActionBar根据文本中是否有文本EditText or not 所以 我做了以下事情 public class NounSearch extends android app Fragment EditText seach
  • 如何在 Xcode 4 中通过一个操作归档多个目标

    我有一个包含多个目标的项目 这些目标都适用于不同的 iOS 应用程序 例如 一个用于精简版的目标 另一个用于专业版的目标 我想立即构建并归档我的所有应用程序 目前 我对每个目标都有一个方案 我用它来独立归档每个应用程序 但现在我必须开始归档
  • 版本 5 上带有 getBackground().setAlpha 的按钮 - 棒棒糖无法正常工作

    我有这段代码 适用于自 API 14 以来的每个版本 但在 Android 5 0 Lollipop 上无法正常工作 以下是我希望按钮出现的方式 单击按钮1 buttonArrivals getBackground setAlpha 180
  • 手动启用时 Firebase Crashlytics 不报告崩溃

    Crashlytics 在没有选择加入报告的情况下也能正常工作 但一旦我根据规定设置了选择加入报告 它就会停止报告任何内容tutorial https firebase google com docs crashlytics customi
  • 如何从SurfaceView绘制到Canvas?

    我正在尝试做简单的画家 问题是Android看起来有三个独立的Canvas并给我它来顺序绘制 我用以下方式制作了用户界面SurfaceView 把霍尔德从中拿走 Override protected void onCreate Bundle
  • 有没有办法在Android上创建一个三角形按钮?

    有没有办法创建一个三角形的按钮 我知道我可以将三角形图像作为背景 但这将使三角形之外的区域可单击 有没有办法固定按钮角 X 和 Y 以便我可以将其变成三角形 您可以覆盖OnTouch http developer android com r
  • Cognito/IAM 策略和 S3 获取对象

    我正在尝试将 S3 和 Cognito 集成到我的 iOS 应用程序中 但到目前为止尚未成功 我相信该错误与我针对 Auth 和 Unauth 用户的 IAM 策略有关 所以这是我的政策 Version 2012 10 17 Stateme
  • 如何在 EKRecurrenceRule 中设置一周中某一天的数组?

    我想在用户选择的特定日期每周添加事件 可以是一个或多个 也可以是一整天 我将用户选择的日期值存储在模型类变量中 但是 当我添加事件并选择日期时 假设今天是星期一 我选择星期二和星期三并保存 然后我查看周一和周三添加的 iPhone 日历 我
  • Android:如何使视图增长以填充可用空间?

    这看起来很简单 但我不知道该怎么做 我有一个带有 EditText 和两个 ImageButtons 的水平布局 我希望 ImageButtons 具有固定大小 并且 EditText 占据布局中的剩余空间 如何才能做到这一点
  • 如何更改锁屏自定义文本(所有者信息)?

    我写了程序代码 String message This is test Settings System putString context getContentResolver Settings Secure LOCK PATTERN EN
  • 如何使用 afnetworking 在后台上传任务

    我正在尝试使用 AFNetworking 上传大文件 并在应用程序处于后台时继续上传 我可以很好地上传文件 但是当我尝试使用后台配置时 应用程序崩溃并显示以下堆栈跟踪 异常 EXC BAD ACCESS 代码 1 地址 0x8000001f
  • Jetpack Compose 部分或开放侧边框

    我正在尝试绘制部分或一侧开放的矩形圆形边框以实现此效果 玩了一下之后我得到了这个 这是通过以下方式完成的 RoundedCornerShape topStartPercent 50 bottomStartPercent 50 start R
  • ormlite 将日期读取为 'yyyy-MM-dd'

    我需要读取给我的 sqlite 数据库 因此我无法更改表中的日期格式 yyyy MM dd 当我尝试使用 ormlite 为我生成对象时 使用以下注释 DatabaseField columnName REVISION DATE dataT
  • OpenGL ES 2.0 屏幕闪烁

    我面临着一个大问题 我正在使用带有 Android 4 0 3 的 Transformer tf101 选项卡 我的应用程序使用自定义 OpenGL ES 2 0 表面 我正在用纹理渲染多个平面 该纹理大约发生变化 每秒 20 次 并通过传
  • 基于BluetoothChat示例通过蓝牙套接字发送文件

    大家好 根据我之前问的一个问题 我已经能够将文件转换为其他字节数组 以便使用以下写入方法 public void sendFile Log d TAG sending data InputStream inputStream null Ur
  • 通用类不会将委托调用转发给具体子类

    鉴于以下情况 protocol EntityType var displayString String get extension String EntityType var displayString String return self

随机推荐

  • 发布vue 的npm包

    1 本地启动一个vue项目 2 在src文件下新建index js import xxx from components xxx vue export default xxx 3 在src文件夹同级新建index js xxx 代表你的模块
  • 在一款芯片中多个时钟域非常常见,跨时钟域检查至关重要。本篇记录的是CDC跨时钟域的基础概念。

    CDC Clock Domain Crossing 跨时钟域 在一款芯片中多个时钟域非常常见 跨时钟域检查至关重要 本篇记录的是CDC跨时钟域的基础概念 时钟域clock domain 以寄存器捕获的时钟来划分时钟域 单时钟域single
  • STL空间配置器allocator详解

    转自 https blog csdn net xy913741894 article details 66974004 stl六大组件简介 我们知道 stl有容器 空间配置器 适配器 迭代器 仿函数以及算法这6个组件 它们六者关系大概如下
  • Ubuntu 22报错:PAM unable to dlopen(pam_tally2.so)

    ubuntu 22安装好后 普通用户一直登录不上 查看 var log auth log发现报错 Aug 18 17 02 02 xx sshd 388903 PAM unable to dlopen pam tally2 so lib s
  • linux如何发送查收邮件的详解

    一 linux用户发送给linux中的其它用户 1 使用命令 yum install sendmail y安装sendmail软件 2 使用yum install mailx y安装 mailx软件 3 使用命令systemctl star
  • 新安装的kali-linux 2022.1无法与其他虚拟机之间互相ping同

    新安装了kali 然后发现虚拟机无法与其他虚拟机互相ping同 也无法被ping 首先虚拟机之间都是nat模式 所有此时要查看不能ping同的虚拟机之间是否在同一个网段 此时要查看你的主机中网络连接的VMnet8的网段 VMnet8为nat
  • 纯Asp实现微信支付

    微信支付的程序文件需要3个 1 生成二唯码供用户扫描的网页 2 支付回调URL 就是当用户扫描二唯码后 微信会调用这个回调用URL 3 微信支付异步通知回调地址 当用户在微信上确认支付后 接收微信支付异步通知 其中第 2 3 个文件需要在支
  • 什么是哈希函数

    什么是hash函数 哈希函数 Hash Function 也称为散列函数 给定一个输入x 它会算出相应的输出H x 哈希函数的主要特征是 输入x可以是任意长度的字符串 输出结果即H x 的长度是固定的 计算 H x 的过程是高效的 对于长度
  • 经验之谈

    谈编程 的确而是一个复杂的问题 我只是一个菜鸟 甚至连菜鸟都算不上 只是喜欢代码而已 看看不同的人写不同的代码吸收他人的智慧之光也是一种享受 网络中精英辈出 什么jsp asp php java c c 真的太多了 需要学的东西确实太多了
  • 安卓报错 Failed to commit install session

    Installation failed due to Failed to commit install session 2076835843 with command cmd package install commit 207683584
  • 27. 移除元素

    Swift func removeElement nums inout Int val Int gt Int 将数据声明为var类型 否则无法对其进行操作 var nums nums 返回值 var count nums count 循环次
  • 数据链路层的主要功能

    数据链路层主要功能 主要功能概述 数据链路层的三个基本问题 1 封装成帧 2 透明传输 3 差错检测 MAC寻址 链路层向网络层提供的服务 1 无确认的无连接服务 2 有确认的无连接服务 3 有确认的面向连接服务 其他知识点 主要功能概述
  • 启动项目报错 Error: listen EADDRINUSE: address already in use :::3301

    服务端启动端口报错Error listen EADDRINUSE address already in use 3301 在宝塔运行node项目时报错 提示已经有3301端口了 现在我们可以找到线程然后关闭就行了 第一步 通过端口号找到线程
  • 使用 webpack 对项目进行打包发布

    打包发布 1 为什么要打包发布 项目开发完成之后 需要使用 webpack 对项目进行打包发布 主要原因有以下两点 开发环境下 打包生成的文件存放于内存中 无法获取到最终打包生成的文件 开发环境下 打包生成的文件不会进行代码压缩和性能优化
  • 复旦大学黄萱菁:自然语言处理中的表示学习

    不到现场 照样看最干货的学术报告 嗨 大家好 这里是学术报告专栏 读芯术小编不定期挑选并亲自跑会 为大家奉献科技领域最优秀的学术报告 为同学们记录报告干货 并想方设法搞到一手的PPT和现场视频 足够干货 足够新鲜 话不多说 快快看过来 希望
  • 【毕设】车牌识别系统的设计与实现

    车牌识别系统的设计与实现 毕设记录 1 前言 源码见评论区 2 开发环境 3 VS2017配置OpenCV运行第一个小程序 19 12 27 3 1 第一个小程序 3 2 参考链接汇总 4 车牌定位 19 12 27 4 1 知识点提要 4
  • python3 查看Django版本

    由于python3 与 Django存在不兼容的问题 需要用相对应的Django版本号跟python3进行匹配 Django版本号地址 https docs djangoproject com en 1 9 releases
  • nlp练习题以及答案(自用)

    2 000 IP 281470860753233 13 08 57 13 10 12 01 15 68 77 下面哪种是由多个 键 值 对组成的无序序列 列表 元组 x 字典 集合 2 000 IP 281470860753233 13 1
  • CentOS7.6安装离线编译安装Redis4.0.9

    下载地址 https redis io download 文件上传至 usr local tar xzf redis 4 0 9 tar gz cd redis 4 0 9 yum install gcc tcl y make MALLOC
  • 想知道微信怎么做指纹支付开发?看这里!

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 作者简介 Henryye 叶轩 来自腾讯微信事业群 主要负责腾讯开源项目TENCENT SOTER GitHub地址 https github com Tencent soter 生