设备:一个开发狗,n个超级狗
一、安装环境:安装超级狗供应商提供的开发套件。我拿到的是2.4版本的。
二、生成开发商认证码:用于写入读取超级狗信息操作。打开开发套件的超级狗工具包,点击身份认证方案->认证代码生成工具,插入开发狗,点击生成认证代码,选择文件路径。生成的认证代码中包含开发商id(vendor),超级狗认证码(authcode)
三、初始化超级狗:初始化超级狗的帐号、口令。打开开发套件的超级狗工具包,点击身份认证方案->初始化工具。
1、点击Auth Code File 后面的open按钮选择第二步中生成的认证代码文件。
2、在Current SO PIN后面的输入框,输入默认的管理员密码abcdefgh。
3、如果不需要修改管理员默认密码,请忽略这一点。如果需要修改管理员的默认密码,请勾选Change SO PIN,在New SO PIN和Confirm SO PIN后面的输入框分别输入新密码和确认密码。注意:若修改管理员密码,请记住新的密码。
4、设置超级狗用户口令:勾选 Set USER PIN,在New USER PIN和Confirm USER PIN后面的输入框分别输入新密码和确认密码。
5、设置超级狗用户名:勾选Set UserName,在User Name后面的输入框输入对应财政部门管理员的帐号。
6、完成以上步骤后,点击Init按钮。若弹窗提示“Init SuperDog Success!”,则初始化成功。
四、安装浏览器插件:打开开发套件的超级狗工具包,点击身份认证方案->浏览器插件安装工具。
五、开发代码:
1、前端代码(angular):
//超级狗begin
$scope.dogMessage = "";
$scope.dogScope = " ";
//获取超级狗配置信息
$http.get('/web/superdog/authentication/getSuperDogConfig', null).then(function (data) {
var data = data.data;
if (data.status && data.code === 200) {
//挑战数据
$scope.challenge = data.info.challenge;
//默认口令
$scope.superdogDefalutPass = data.info.superDogDefaultPass;
//超级狗认证码
$scope.authCode = data.info.superDogAuthcode;
}
});
//非ie、谷歌浏览器下在html页面里面添加object
superDogService.embedTag();
//获取超级狗插件对象
$scope.objAuth = superDogService.getAuthObject();
loadFunc();
function checkDog()
{
var stat = "";
//谷歌浏览器
if (navigator.userAgent.indexOf("Chrome") > 0) {
//获取超级狗中的用户名
$scope.objAuth.GetUserNameEx($scope.dogScope, $scope.authCode);
}
else {
//判断是否安装控件
if($scope.objAuth.hasOwnProperty("Open")==false){
$scope.dogMessage ="您未安装系统必需的控件";
setTimeout(checkDog, 5000);
return;
}
//打开超级狗
stat = $scope.objAuth.Open($scope.dogScope, $scope.authCode);
if(0 != stat)
{
$scope.model.use.useName ="";
$scope.dogMessage = superDogService.reportStatus(stat);
}
else
{
$scope.dogMessage ="";
//获取超级狗中的用户名
stat = $scope.objAuth.GetUserName();
if (stat != 0) {
$scope.model.use.useName ="";
$scope.dogMessage = superDogService.reportStatus(stat);
}else {
$scope.model.use.useName = $scope.objAuth.UserNameStr;
if($scope.model.use.useName==''){
$scope.dogMessage ="设备未绑定帐号!";
}
}
$scope.objAuth.Close();
}
}
setTimeout(checkDog, 1000);
}
function loadFunc()
{
if (navigator.userAgent.indexOf("Window") > 0)
{
if (navigator.userAgent.indexOf("Chrome") > 0) //Chrome
{
window.addEventListener("message", function (event) {
if (event.source != window) {
return;
}
if (event.data.type == "SNTL_FROM_HOST") {
var ReturnText = event.data.text;
//获取超级狗中返回的用户名
if ("GetUserNameEx" == ReturnText.InvokeMethod) {
if (0 == ReturnText.Status) {
$scope.model.use.useName = ReturnText.UserNameStr;
$scope.dogMessage ="";
if($scope.model.use.useName==''){
$scope.dogMessage ="设备未绑定帐号!";
}
}
else {
$scope.model.use.useName ="";
$scope.dogMessage = superDogService.reportStatus(parseInt(ReturnText.Status));
}
}
//获取超级狗中返回的摘要加密串,发送到服务端验证
else if ("GetDigestEx" == ReturnText.InvokeMethod) {
if (0 == ReturnText.Status) {
$http.get('/web/superdog/authentication/verifyDigest', {params:{dog_id:ReturnText.DogIdStr,challenge:$scope.challenge,digest:ReturnText.DigestStr}}).then(function (data) {
var data = data.data;
if (data.status && data.code === 200) {
if (data.info != 0) {
$scope.dogMessage = superDogService.reportStatus(data.info);
}
else {
//验证通过做登录操作
$scope.events.submitUse();
}
}
});
}
else {
$scope.dogMessage = superDogService.reportStatus(parseInt(ReturnText.Status));
}
}
}
return;
}, false);
}
else if (window.ActiveXObject || "ActiveXObject" in window) //IE
{
//$scope.objAuth.SetCheckDogCallBack("insertDog", "removeDog");
}
setTimeout(checkDog, 1000);
}
else if (navigator.userAgent.indexOf("Mac") > 0 || navigator.userAgent.indexOf("Linux") > 0)
{
setTimeout(checkDog, 1000);
}
}
function loginCheck(){
var stat = "";
if (window.ActiveXObject || "ActiveXObject" in window) //IE
{
//Add onfocus event
var obj = document.getElementById("password");
if (Object.hasOwnProperty.call(window, "ActiveXObject") && !window.ActiveXObject) {// is IE11
obj.addEventListener("onfocus", function () {
$scope.dogMessage = "";
}, false);
}
else {
obj.attachEvent("onfocus", function () {
$scope.dogMessage = "";
});
}
}
//Chrome
if (navigator.userAgent.indexOf("Chrome") > 0) {
//超级狗口令验证
$scope.objAuth.GetDigestEx($scope.dogScope, $scope.authCode, $scope.superdogDefalutPass, $scope.challenge);
return false;
} else {
//打开超级狗
stat = $scope.objAuth.Open($scope.dogScope, $scope.authCode);
if (stat != 0) {
$scope.dogMessage = superDogService.reportStatus(stat);
return false;
}
//超级狗口令验证
stat = $scope.objAuth.VerifyUserPin($scope.superdogDefalutPass);
if (stat != 0) {
$scope.objAuth.Close();
$scope.dogMessage = superDogService.reportStatus(stat);
return false;
}
//获取超级狗id
stat = $scope.objAuth.GetDogID();
if (stat != 0) {
$scope.objAuth.Close();
$scope.dogMessage = superDogService.reportStatus(stat);
return false;
}
//获取超级狗摘要加密串
stat = $scope.objAuth.GetDigest($scope.challenge);
if (stat != 0) {
$scope.objAuth.Close();
$scope.dogMessage = superDogService.reportStatus(stat);
return false;
}
//服务端验证摘要加密串
$http.get('/web/superdog/authentication/verifyDigest', {
params: {
dog_id: $scope.objAuth.DogIdStr,
challenge: $scope.challenge,
digest: $scope.objAuth.DigestStr
}
}).then(function (data) {
var data = data.data;
if (data.status && data.code === 200) {
stat = data.info;
if (stat != 0) {
$scope.objAuth.Close();
$scope.dogMessage = superDogService.reportStatus(stat);
return;
}
else {
//验证通过做登录操作
$scope.events.submitUse();
}
}
});
$scope.objAuth.Close();
return true;
}
}
//超级狗end
上面superDogService对应的js文件代码
//超级狗
define (['angular', 'angularUiRouter', 'uiRouterExtras', 'oclazyload'], function (angular) {
return angular.module ('superDogFunc', ['ui.router', 'oc.lazyLoad',
'ct.ui.router.extras'])
.factory('superDogService',['$rootScope',function($rootScope){
var superDogService={
};
function getAuthObjectChrome(){
var obj = new AuthObject();
return obj;
};
function AuthObject() {
if (typeof AuthObject._initialized == "undefined") {
// GetUserNameEx
AuthObject.prototype.GetUserNameEx = function (scope, authCode) {
//console.log("enter GetUserNameEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "GetUserNameEx", "Scope": scope, "AuthCode": authCode} }, "*");
return 0;
};
// GetDigestEx
AuthObject.prototype.GetDigestEx = function (scope, authCode, password, challenge) {
//console.log("enter GetDigestEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "GetDigestEx", "Scope": scope, "AuthCode": authCode, "UserPin": password, "Challenge": challenge} }, "*");
return 0;
};
// RegisterUserEx
AuthObject.prototype.RegisterUserEx = function (scope, authCode, username, password) {
//console.log("enter RegisterUserEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "RegisterUserEx", "Scope": scope, "AuthCode": authCode, "Name": username, "UserPin": password } }, "*");
return 0;
};
// ChangeUserPinEx
AuthObject.prototype.ChangeUserPinEx = function (scope, authCode, oldPassword, newPassword) {
//console.log("enter ChangeUserPinEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "ChangeUserPinEx", "Scope": scope, "AuthCode": authCode, "OldPin": oldPassword, "NewPin": newPassword } }, "*");
return 0;
};
// SetUserDataEx
AuthObject.prototype.SetUserDataEx = function (scope, authCode, password, type, offset, data) {
//console.log("enter SetUserDataEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "SetUserDataEx", "Scope": scope, "AuthCode": authCode, "UserPin": password, "Type": type, "Offset": offset, "Data": data } }, "*");
return 0;
};
// GetUserDataEx
AuthObject.prototype.GetUserDataEx = function (scope, authCode, type, offset, size) {
//console.log("enter GetUserDataEx()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "GetUserDataEx", "Scope": scope, "AuthCode": authCode, "Type": type, "Offset": offset, "Size": size } }, "*");
return 0;
};
// EnumDog
AuthObject.prototype.EnumDog = function (authCode) {
//console.log("enter EnumDog()");
window.postMessage({ type: "SNTL_FROM_PAGE", text: { "InvokeMethod": "EnumDog", "AuthCode": authCode} }, "*");
return 0;
};
AuthObject._initialized = true;
}
}
superDogService.embedTag = function(){
if (window.ActiveXObject || "ActiveXObject" in window) {//IE
;
}
else if (navigator.userAgent.indexOf("Chrome") > 0) {//Chrome
;
}
else {
var temp = document.body.innerHTML;
var tag = "";
document.body.innerHTML = tag + temp;
}
};
superDogService.getAuthObject = function(){
var objAuth;
if (window.ActiveXObject || "ActiveXObject" in window) //IE
{
objAuth = document.getElementById("AuthIE");
}
else if (navigator.userAgent.indexOf("Chrome") > 0) {
objAuth = getAuthObjectChrome();
}
else {
objAuth = document.getElementById("AuthNoIE");
}
return objAuth;
};
superDogService.reportStatus = function(status){
var text = "未知的认证状态代码";
switch (status) {
case 0: text = "请求已成功完成";
break;
case 1: text = "请求超出数据文件的范围";
break;
case 3: text = "系统内存不足";
break;
case 4: text = "打开的登录会话数目过多";
break;
case 5: text = "访问被拒绝";
break;
case 7: text = "请您插入U-key设备!";
break;
case 8: text = "加密/解密的数据长度太短";
break;
case 9: text = "输入函数的句柄无效";
break;
case 10: text = "无法识别文件标识符";
break;
case 15: text = "无效的 XML 格式";
break;
case 18: text = "未找到待升级的超级狗";
break;
case 19: text = "未找到所需的 XML 标记,或者二进制数据的内容已丢失或无效";
break;
case 20: text = "该超级狗不支持升级请求";
break;
case 21: text = "升级计数器设置不正确";
break;
case 22: text = "输入的开发商代码无效";
break;
case 24: text = "输入的时间值超出被支持的数值范围";
break;
case 26: text = "升级要求回执数据,但输入参数ack_data 为 NULL";
break;
case 27: text = "程序在终端服务器上运行";
break;
case 29: text = "V2C 文件中使用了未知算法";
break;
case 30: text = "签名验证失败";
break;
case 31: text = "特征不可用";
break;
case 33: text = "API 和超级狗运行环境(License Manager)通讯错误";
break;
case 34: text = "API 不识别开发商代码";
break;
case 35: text = "无效的 XML 格式";
break;
case 36: text = "无效的 XML 范围";
break;
case 37: text = "当前连接的超级狗数目过多";
break;
case 39: text = "会话被中断";
break;
case 41: text = "特征已失效";
break;
case 42: text = "超级狗的运行环境版本太旧";
break;
case 43: text = "与超级狗通讯中出现 USB 通信错误";
break;
case 45: text = "系统时钟已被篡改";
break;
case 46: text = "安全通道中发生了通信错误";
break;
case 50: text = "不能找到与范围匹配的特征";
break;
case 54: text = "文件中的升级计数器的数值小于超级狗中的升级计数器的数值,不允许安装 V2C文件";
break;
case 55: text = "文件中的升级计数器的数值大于超级狗中的升级计数器的数值,不允许安装 V2C文件";
break;
case 400: text = "未找到 API 的动态库";
break;
case 401: text = "API 的动态库无效";
break;
case 500: text = "对象的初始化不正确";
break;
case 501: text = "无效的函数参数";
break;
case 502: text = "两次登录到同一对象";
break;
case 503: text = "从同一对象注销两次";
break;
case 525: text = "系统或平台的使用不正确";
break;
case 698: text = "未实施所请求的功能";
break;
case 699: text = "API 中内部错误";
break;
case 802: text = "参数为空";
break;
case 803: text = "认证代码长度不正确";
break;
case 804: text = "请先登录";
break;
case 810: text = "口令长度不正确";
break;
case 811: text = "参数长度不正确";
break;
case 812: text = "用户数据长度不正确";
break;
case 813: text = "用户名长度不正确";
break;
case 814: text = "认证因子长度不正确";
break;
/*case 820: text = "Hardware internal error!";
break;*/
case 821: text = "请先验证管理员口令";
break;
case 822: text = "请先验证用户口令";
break;
case 823: text = "缓冲区长度不足";
break;
case 824: text = "认证动态库初始化失败";
break;
case 825: text = "用户口令被锁定";
break;
case 831: text = "验证用户口令失败(累计:1 次)";
break;
case 832: text = "验证用户口令失败(累计:2 次)";
break;
case 833: text = "验证用户口令失败(累计:3 次)";
break;
case 834: text = "验证用户口令失败(累计:4 次)";
break;
case 835: text = "验证用户口令失败(累计:5 次)";
break;
case 836: text = "验证用户口令失败(累计:6 次)";
break;
case 837: text = "验证用户口令失败(累计:7 次)";
break;
case 838: text = "验证用户口令失败(累计:8 次)";
break;
case 839: text = "验证用户口令失败(累计:9 次)";
break;
case 840: text = "验证用户口令失败(累计:10 次)";
break;
case 841: text = "验证用户口令失败(累计:11 次)";
break;
case 842: text = "验证用户口令失败(累计:12 次)";
break;
case 843: text = "验证用户口令失败(累计:13 次)";
break;
case 844: text = "验证用户口令失败(累计:14 次)";
break;
case 845: text = "验证用户口令失败(累计:15 次),用户口令被锁定";
break;
case 900: text = "用户绑定UKey信息异常,请联系管理员";
break;
case 901: text = "认证失败";
break;
case 902: text = "生成挑战数据失败";
break;
case 903: text = "用户名包含不支持的字符";
break;
case 904: text = "请输入口令";
break;
case 905: text = "口令长度须在 6-16 字节之间";
break;
case 906: text = "口令包含不支持的字符";
break;
case 907: text = "请输入用户名";
break;
case 908: text = "请再次输入口令";
break;
case 909: text = "口令长度须在 6-16 字节之间";
break;
case 910: text = "口令包含不支持的字符";
break;
case 911: text = "口令和确认口令不一致";
break;
case 912: text = "请输入当前口令";
break;
case 913: text = "请输入新口令";
break;
case 914: text = "用户名长度须在 1-32 字节之间";
break;
case 915: text = "此超级狗已经注册过,不支持再次注册";
break;
case 916: text = "在 java.library.path 指定的文件夹找不到dog_auth_srv 库文件";
break;
case 917: text = "获取挑战数据失败";
break;
case 918: text = "获取挑战数据失败";
break;
case 919: text = "找不到会话文件,请确认会话文件夹已经正确创建和设置。";
break;
case 920: text = "加载动态库失败:dog_auth_srv_php.dll,请确认配置文件已经正确设置";
break;
}
return text;
};
return superDogService;
}])
});
2、后端代码:
public class Authentication extends AbstractAction {
//加载第三方动态链接库
static {
try {
String path = Thread.currentThread().getContextClassLoader().getResource("").toString();
path = path.replace("file:/", "").replace("classes/", "");
//判断操作系统
Properties prop = System.getProperties();
String os = prop.getProperty("os.name");
String dataModel = System.getProperty("sun.arch.data.model");
//linux系统
if (os != null && os.toLowerCase().indexOf("linux") > -1) {
log.info("操作系统:" + dataModel + "位linux系统");
path = "/" + path;
if (dataModel.equals("64")) {
System.load(path + "libdog_auth_srv_x64.so");
} else {
System.load(path + "libdog_auth_srv.so");
}
} else {
log.info("操作系统:" + dataModel + "位windows系统");
if (dataModel.equals("64")) {
System.load(path + "dog_auth_srv_x64.dll");
} else {
System.load(path + "dog_auth_srv.dll");
}
}
} catch (Exception e) {
log.info("加载动态库异常:" + e);
throw new RuntimeException(e);
}
}
/**
* 获取挑战数据
*
* @param status
* @return
*/
public native static String getChallenge(int status[]);
/**
* 验证加密的挑战数据
*
* @param vendor_id 开发商 ID
* @param dog_id 超级狗 ID
* @param challenge 挑战数据
* @param digest 由客户端生成的加密的摘要字符串
* @param factor 认证因子
* @return
*/
public native static int verifyDigest(int vendor_id, int dog_id, String challenge, String digest, String factor);
/**
* Description:获取超级狗配置信息(包含挑战数据、超级狗默认密码、超级狗认证码)
*
* @param
* @return java.lang.String
* @Author: wtl
* @Date: 2019/3/16 16:54
*/
@ResponseBody
@RequestMapping("getSuperDogConfig")
public Object jsonObject() {
//获取挑战数据
String challenge = null;
try {
int[] dll_status = {0};
challenge = getChallenge(dll_status);
} catch (UnsatisfiedLinkError e1) {
log.info(e1);
throw new RuntimeException(e1);
} catch (NoClassDefFoundError e1) {
log.info(e1);
throw new RuntimeException(e1);
} catch (Exception e1) {
log.info(e1);
throw new RuntimeException(e1);
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("challenge", challenge);
//超级狗默认密码
jsonObject.put("superDogDefaultPass", ConfigConstant.SUPERDOG_DEFALUTPASS);
//超级狗认证码
jsonObject.put("superDogAuthcode", ConfigConstant.SUPERDOG_AUTHCODE);
return jsonObject;
}
/**
* Description:验证加密的摘要字符串
*
* @param dog_id 超级狗id
* @param challenge 挑战数据
* @param digest 由客户端生成的加密的摘要字符串
* @return int 返回 0 验证通过 900 用户绑定UKey信息异常 901 认证失败
* @Author: wtl
* @Date: 2019/3/16 16:54
*/
@ResponseBody
@RequestMapping("verifyDigest")
public int verifyDigest(int dog_id, String challenge, String digest) {
int status;
try {
status = verifyDigest(ConfigConstant.SUPERDOG_VENDOR_ID, dog_id, challenge, digest, ConfigConstant.SUPERDOG_FACTOR);
log.debug("超级狗验证结果:" + status);
} catch (UnsatisfiedLinkError e1) {
status = 901;
log.info(e1);
} catch (NoClassDefFoundError e1) {
status = 901;
log.info(e1);
} catch (Exception e) {
status = 901;
log.info(e);
}
return status;
}
}