最近在整理关于实时风控决策系统的内容,今天抽空写了一篇如何快速部署的简单攻略吧。
接入只需4步
具体步骤
Step 1:获取AppId、AppSecret;
前往顶象管理后台,在实时风险决策的二级菜单“应用管理”中获取;
PS:未开通服务的,需要先申请开通服务。
Step 2:前端接入,即设备指纹埋点;
支持Web接入,支持IE8+、Chrome、Firefox、360浏览器、QQ浏览器等主流浏览器及Android、iOS上的内嵌Webview。
PS:提示:设备指纹token具有时效性,超过一定时间会过期,请勿自行缓存
重要:因终端用户的设备网络环境和设备版本等因素,设备指纹采集率并不能一定达到100%,可能会存在极少部分未能正常采集到的情况。
所以在集成指纹服务的时候,请尽量避免对指纹信息强依赖。
1. web接入
1.1 环境要求
兼容IE8+,Chrome,Firefox,360浏览器,QQ浏览器等主流浏览器。
1.2 引入JS
在页面 HTML 中引入const-id.js,代码如下:
<script src="https://cdn.dingxiang-inc.com/ctu-group/constid-js/index.js"></script>
1.3 生成token
页面加载后,初始使用,需要在 JavaScript 中调用_dx.ConstID(options, callback)方法,生成token,代码形如:
var options = {
appId: '【这里填写 AppId】', // 唯一标识,必填
server: 'https://constid.dingxiang-inc.com/udid/c1', // ConstId 服务接口,可选
userId: '【这里填写 userID】' // 用户标识,可选
};
_dx.ConstID(options, function (e, id) {
if (e) {
// console.log('error: ' + e);
return;
}
// console.log('token is ' + id);
// console.log(_dx.constID === id); // true
});
执行成功后,页面中将会有一个全局变量_dx,可以通过_dx.constID访问这个值。也可以继续调用上面的初始化方法,同一个浏览器多次初始化返回的值相同。
options 字段说明
字段 | 类型 | 是否必填 | 说明 |
---|---|---|---|
AppId | String | 是 | 当前应用的标识,需要联系工作人员获取 |
server | String | 否 | 服务接口,可选,如不填,则默认会用云服务接口 |
scene | String | 否 | 场景标识,例如login、survey等 |
userId | String | 否 | 业务方的用户唯一标识,例如用户名、用户ID、手机号、Email等 |
2. Android接入
2.1 环境要求
条目 | 说明 |
---|---|
开发目标 | Android 4.0+ |
开发环境 | Android Studio 3.0.1 或者 Eclipse + ADT |
CPU架构 | ARM 或者 x86 |
SDK三方依赖 | 无 |
2.2 集成SDK
2.2.1 下载SDK
点击下载demo(仅做代码配置演示使用,其中appId请在顶象后台申请,SDK需要替换为链接中下载的SDK)
2.2.2 Android Studio
集成SDK包集成内容:
- libs文件夹下的jar和so
- assets文件夹下的配置文件
把libs下jar和so库放到相应模块的libs目录下,assets下的文件放置到项目assets下
在该Module的build.gradle中如下配置:
android{
sourceSets {
main {
jniLibs.srcDirs = ['libs']
assets.srcDirs = ['assets']
}
}
packagingOptions {
doNotStrip "**/libDX*.so"
}
}
repositories{
flatDir{
dirs 'libs'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation files('libs/dx-risk-x.x.x.jar')
}
2.2.3 添加SDK所需权限
<!-- 必选-默认申请 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 可选-6.0或以上需动态申请 -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2.2.4 Proguard混淆配置
-dontwarn com.dx.mobile.**
-dontwarn *.com.dx.mobile.**
-dontwarn *.com.mobile.strenc.**
-keep class com.dx.mobile.risk.**{*;}
-keep class com.security.inner.**{*;}
-keep class *.com.dx.mobile.**{*;}
-keep class *.com.mobile.strenc.**{*;}
2.2.5 API 6.0或以上动态权限申请说明
需要动态申请权限如下:
android.permission.WRITE_EXTERNAL_STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.READ_PHONE_STATE
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
动态申请代码实例
(Activity下):protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
// API 23或以上的动态申请权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String[] permissionArray = {
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.READ_PHONE_STATE",
};
this.requestPermissions(permissionArray, 1);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// start getToken
new Thread(new Runnable() {
@Override
public void run() {
HashMap<String, String> params = new HashMap<String, String>();
String token = DXRisk.getToken("appid", params);
}
}).start();
}
2.3 接口使用说明
2.3.1 方法和参数说明
功能描述
采集端的设备指纹信息,上传至风控后台,再由风控后台返回token。 该API为耗时操作,因此必须在非主线程上调用,否则会抛异常。
方法说明
DXRisk.java 该类是DxRisk SDK的风控组件接口,负责采集本地信息并返回用户前端token。
初始化
setupSDK使用前必须调用先setup,setup主要用于数据/环境初始化,一般在Application的onCreate下调用:
/**
* 初始化参数,环境
* @param context
* @return
*/
public static boolean setup(Context context)
PS:下列两种方式获取token在网络通畅的情况下没有任何的不同。
常规Token
/**
* @return token 通常返回长度为40的字符串。在网络卡顿或不通的情况下,返回4-5k的字符串。
* @throws DXRiskErrorException 如在主线程调用本API,或者appId为空等等,则会抛出该异常
*/
public static String getToken(String appId, HashMap<String, String> paramsMap) throws DXRiskErrorException
精简Token
获取轻量级Token可获取的设备信息信息远少于getToken(),可能会造成在判断设备是否有风险时出现较大误差,请谨慎使用。
/**
`* @return token 通常返回长度为40的字符串。在网络卡顿或不通的情况下,返回1k的字符串。
`* @throws DXRiskErrorException 如在主线程调用本API,或者appId为空等等,则会抛出该异常
*/
public static String getLightToken(String appId, HashMap<String, String> paramsMap) throws DXRiskErrorException
2.3.2 使用示例
(1) 初始化setup
建议Application.onCreate下调用
@Override
public void onCreate() {
super.onCreate();
// 环境初始化
DXRisk.setup(this);
}
(2) 获取token
整个过程由于是耗时操作,必须要在非主线程上执行,否则会crash
new Thread(){
@Override
public void run() {
/* 私有化配置 */
HashMap<String, String> params = new HashMap<String, String>();
// 私有化部署服务端url
params.put(DXRisk.KEY_URL, "https://constid.dingxiang-inc.com");
// 开启线上数据备份
params.put(DXRisk.KEY_BACKUP, DXRisk.VALUE_ENABLE_BACKUP);
// 设置请求token超时时长ms,不设置默认为500ms
parsms.put(DXRisk.KEY_DELAY_MS_TIME, "2000");
// 开通服务后可在实时风险决策的菜单获取
String appId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// 获取设备指纹token
final String token = DXRisk.getToken(appId, params);
// TODO 把token通过Post请求,传到用户后端
}
}.start();
2.3.3 异常说明
在获取token过程中,如果因为网络超时或者加解密失败,该接口有可能会返回为null,同时会输出tag为DXRISK的错误信息,具体描述如下:
DXRISK_REQUEST_NETWORK_ERR -1001 //网络链接失败
DXRISK_REQUEST_DECRYPT_ERR -1002 //数据解密错误
DXRISK_REQUEST_UNCOMPRESS_ERR -1003 //解压错误
DXRISK_REQUEST_RESPONSE_EMPTY_ERR -1004 //返回为空
DXRISK_REQUEST_DATA_PARSE_ERR -1005 //数据解析失败
DXRISK_REQUEST_DIRTY_DATA_ERR -1006 //脏数据
DXRISK_CONST_ID_EMPTY -1007 //constid为空
3 iOS接入
Apple Store上架请特别注意(2.2.3 节)
3.1环境需求说明
条目 | 说明 |
---|---|
兼容平台 | iOS 8.0+ |
开发环境 | XCode 4.0 + |
CPU架构 | armv7, arm64, i386, x86_64 |
SDK依赖 | libz, libresolv, libc++ , SystemConfiguration.framework , CoreLocation.framework , CoreTelephony.framework |
3.2集成SDK
3.2.1 下载SDK
点击下载SDK,SDK的目录结构如下:
dx-risk-iOS-x.x.x-xxxxxxx目录 DXRisk sdk
- DXRisk.framework 不带idfa获取逻辑的Dynamic Library Framework
- DXRiskWithIDFA.framework 带idfa获取逻辑的Dynamic Library Framework
- DXRiskStatic.framework 不带idfa获取逻辑的Static Library Framework
- DXRiskStaticWithIDFA.framework 带idfa获取逻辑的Static Library Framework
3.2.2 将SDK接入XCode
(1) 导入Framework
DXRisk.framework,DXRiskWithIDFA.framework,DXRiskStatic.framework,DXRiskStaticWithIDFA.framework 其中之一直接拖入工程目录中,或者右击总文件夹添加文件。
- 如果App中包含广告相关的功能,则选择DXRiskWithIDFA.framework 或者 DXRiskStaticWithIDFA.framework,该版本可以提供更精准的token
- 如果没有广告,获取idfa可能导致拒绝上架,此时请选择DXRisk.framework 或者 DXRiskStatic.framework
(2) 添加FrameWork到工程
若在项目中添加DXRisk.framework或者DXRiskWithIDFA.framework其中之一,选择Target -> General,在Frameworks,Libraries,and Embedded Content中,将DXRisk.framework或者DXRiskWithIDFA.framework 对应的 Embed 切换到Embed & Sign。如下图:
若在项目中添加DXRiskStatic.framework或者DXRiskStaticWithIDFA.framework其中之一,需要在Build Settings -> Other Linker Flags 设置 -ObjC 如下图:
(3) 配置打包脚本
以下的操作仅限导入DXRisk.framework ,DXRiskWithIDFA.framework动态库
此步骤主要是解决上传Store架构不符合的问题,如项目中已配置过Carthage或有其他相关的打包Framework调整脚本,可略过此步自行调整 选择Target -> Build Phases,点击+按钮,添加如下脚本:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
3.3 接口使用说明
3.3.1方法和参数说明
// 风控组件:DXRiskManager类
@interface DXRiskManager : NSObject
// 字符串常量
extern NSString* const DXRiskManagerKeyUserId;
extern NSString* const DXRiskManagerKeyEmail;
extern NSString* const DXRiskManagerKeyPhone;
extern NSString* const DXRiskManagerKeyUserExtend1;
extern NSString* const DXRiskManagerKeyUserExtend2;
extern NSString* const DXRiskManagerKeyURL;//私有化服务器地址
extern NSString* const DXRiskManagerKeyBackup;//私有化下使用,将数据备份到顶象服务器(开启为DXRiskManagerKeyBackupEnable 值)
extern NSString* const DXRiskManagerKeyBackupAppId; // 私有化下使用,指定数据备份到顶象服务器的AppId
extern NSString* const DXRiskManagerKeyDegradeNotify;//数据降级通知,若打开,服务端会有响应的降级统计
extern NSString* const DXRiskManagerKeyCountry;//国家地区设置,默认中国
extern NSString* const DXRiskManagerKeyDelayMsTime; //可填设置请求超时毫秒时间(默认值为 500 ,范围是:【100 : 3000】)
// NoticeDegrade参数
/* The NoticeDegrade Value. This value only be used pair with key:DXRiskManagerKeyDegradeNotify to notify token degrade. */
extern NSString* const DXRiskManagerKeyDegradeNotifyEnable;
// Backup参数
/* The Backup Value. This value only be used pair with key:DXRiskManagerKeyBackup to set data backup. */
extern NSString* const DXRiskManagerKeyBackupEnable;
// Country参数
/* The Country Value. This value only be used pair with key:DXRiskManagerKeyCountry to set country. */
extern NSString* const DXRiskManagerCountryChina;
/* The Country Value. This value only be used pair with key:DXRiskManagerKeyCountry to set country. */
extern NSString* const DXRiskManagerCountryIndonesia;
/**
采集端的设备指纹信息,上传至风控后台,再由风控后台返回token。
该API为耗时操作,因此必须在非主线程上调用。
@param appId appId 开通服务后可在实时风险决策的二级菜单“应用管理”中获取
@param extendsParams 额外配置项
@return token
*/
+ (NSString *)getToken:(NSString *)appId extendParams:(NSDictionary *)extendsParams;
/**
DXRiskManager -- 初始化方法
*/
+ (BOOL)setup;
@end
3.3.2使用示例
示例一:Native
// 整个过程由于是耗时操作,必须要在非主线程上执行,否则会阻塞UI。如果本身已经在非UI线程上执行,则不需要另开线程
dispatch_queue_t dxrisk_queue = dispatch_queue_create("com.dingxiang.dxrisk", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(dxrisk_queue, ^{
// 根据业务逻辑,填充自定义字段
NSDictionary *dic = @{DXRiskManagerKeyUserId: @"123456"};
// 如需自定义服务端URL,填充DXRiskManagerKeyURL字段,如需备份私有化数据填充DXRiskManagerKeyBackup字段,如下注释
// NSDictionary *dic = @{DXRiskManagerKeyUserId: @"123456",DXRiskManagerKeyURL:@"http://xxxxxxx",DXRiskManagerKeyBackup:DXRiskManagerKeyBackupEnable};
// 如需统计设备降级率,填充DXRiskManagerKeyDegradeNotify字段,如下注释
// NSDictionary *dic = @{DXRiskManagerKeyUserId: @"123456",DXRiskManagerKeyDegradeNotify:DXRiskManagerKeyDegradeNotifyEnable};
// 获取token
// 注意:token最好不要保存在某个局部变量或者字段,每次使用时,都通过API获取。
//初始化
BOOL isSuccess = [DXRiskManager setup];
NSLog(@"setup success: %@" , isSuccess ? @"YES":@"NO");
// 获取token
// 注意:token最好不要保存在某个局部变量或者字段,每次使用时,都通过API获取。
NSString *constID = [DXRiskManager getToken:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" extendsParams:dic]; NSLog(@"token: %@", token);
// TODO 把token通过Post请求,传到业务后台。
// 下面是模拟频繁调用的过程
while(TRUE) {
NSLog(@"constID: %@", [DXRiskManager getToken:@"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" extendsParams:dic]);
[NSThread sleepForTimeInterval:.5];
}
});
示例二:JavaScript
将相关变量导入JSContext
JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
jsContext[@"DXRiskManager"] = [DXRiskManager class];
jsContext[@"DXRiskManagerKeyUserId"] = DXRiskManagerKeyUserId;
jsContext[@"DXRiskManagerKeyBackup"] = DXRiskManagerKeyBackup;
jsContext[@"DXRiskManagerKeyURL"] = DXRiskManagerKeyURL;
jsContext.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
context.exception = exceptionValue;
NSLog(@"异常信息:%@", exceptionValue);
};
// 根据业务逻辑,填充自定义字段(同Native使用示例)
var isSuccess = DXRiskManager.setup()
var token = DXRiskManager.getToken('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' , {[DXRiskManagerKeyUserId]: '123456'})
私有化部署的用户,使用4.8.0以上版本的SDK, DXRiskManagerKeyURL填写规则为ip+port(http://ip:port)或者域名(http://domain.com),注意后面不要拼"/"
3.3.3 异常说明
在获取token过程中,如果因为网络超时或者加解密失败,该接口有可能会返回为null,同时会输出tag为DXRISK的错误信息,具体描述如下:
DXRISK_REQUEST_NETWORK_ERR -1001 //网络链接失败
DXRISK_REQUEST_DECRYPT_ERR -1002 //数据解密错误
DXRISK_REQUEST_UNCOMPRESS_ERR -1003 //解压错误
DXRISK_REQUEST_RESPONSE_EMPTY_ERR -1004 //返回为空
DXRISK_REQUEST_DATA_PARSE_ERR -1005 //数据解析失败
DXRISK_REQUEST_DIRTY_DATA_ERR -1006 //脏数据
DXRISK_CONST_ID_EMPTY -1007 //constid为空
4 微信小程序接入
js接入
一、下载设备指纹js
二、获取密钥
未注册用户可在顶象官网进行账号注册,创建应用获取应用密钥AppID和AppSecret。
三、使用
1.代码接入
const ConstId = require('本地设备指纹js存放路径')
Page({
onLoad: function () {
new ConstId({
appId: '【这里填写在顶象官网申请到的 AppID】', // 唯一标识,必填
server: '' // constId 私有化服务接口,选填
}, (e, id) => {
if (e) {
console.log(e)
return
}
console.log('constId:', id)
})
}
})
- SaaS用户在小程序后台配置业务域名https://constid.dingxiang-inc.com,私有化用户配置部署域名,测试阶段可以开启微信开发者工具右上角详情->本地设置->“不校验域名”。
后续将持续更新后端接入示例代码,记得关注呀!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。