认证思路:
1.用户登录时输入口令或登录后在特定权限要求下弹窗输入口令。
2.根据用户名从数据库中查询对应的令牌信息,获得上一次认证时回写的内容,验证本次口令有效性。
操作方法:
1.数据库中用户表增加字段“令牌序列号”,记录打印在令牌上的产品序号。
2.数据库中增加新表,记录令牌信息,字段包含令牌序列号、密钥、成功值、漂移值等。其中令牌序列号关联用户表中对应的字段。需提前将令牌的序列号和秘钥录入数据库,成功值和漂移值初始化0。
3.将ET_OTPVerify.dll复制到项目bin目录下。
4.以非托管方式调用ET_OTPVerify.dll,认证页面增加以下代码:
[DllImport("ET_OTPVerify.dll")]
public static extern int ET_CheckPwdz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int authwnd, UInt64 lastsucc, string otp, int otplen, ref UInt64 currsucc, ref int currdft);
[DllImport("ET_OTPVerify.dll")]
public static extern int ET_Syncz201(string authkey, UInt64 t, UInt64 t0, uint x, int drift, int syncwnd, UInt64 lastsucc, string otp1, int otp1len, string otp2, int otp2len, ref UInt64 currsucc, ref int currdft);
/* =============================================================================
* Function : ET_CheckPwdz201
* Description: OTP Z201(TOTP) 认证接口
* Parameter :
* authkey 令牌密钥(令牌提供商提供) //应存入数据库中,使用时select
* t 当前时间相对UTC Epoch秒数
* t0 起始参考时间相对UTC Epoch秒数(默认为0)
* x TOTP变化周期(默认为60秒)
* drift 漂移值(用于时间校准) //数据库中取,第一次给0.
* authwnd 认证范围, 通常是0-20
* lastsucc 前一次认证成功的相对UTC Epoch秒数(为防止重放攻击) //数据库中取,第一次给0.
* otp 需要认证的动态口令
* otplen 需要认证的动态口令长度, 通常是6
* currsucc 认证成功后的相对UTC Epoch秒数 //认证成功后应写入数据库,供下次调用。
* currdft 认证成功后的当前漂移次数 //认证成功后应写入数据库,供下次调用。
*
* return : 0 - 成功, 其他值为错误.
*
*int __stdcall ET_CheckPwdz201(char *authkey, uint64_t t, uint64_t t0,
* unsigned int x, int drift, int authwnd, uint64_t lastsucc,
* const char *otp, int otplen, uint64_t *currsucc, int *currdft);
=============================================================================
* Function : ET_Syncz201
* Description: OTP Z201(TOTP) 同步接口
* Parameter :
* authkey 令牌密钥,已经加密过的,需要对其进行解密
* t 当前时间相对UTC Epoch秒数
* t0 起始参考时间相对UTC Epoch秒数(默认为0)
* x TOTP变化周期(默认为60秒)
* drift 漂移值
* syncwnd 同步范围, 通常是0-40
* lastsucc 前一次认证成功的相对UTC Epoch秒数(为防止重放攻击)
* otp1 需要同步的第一个动态口令
* otp1len 需要同步的第一个动态口令长度, 通常是6
* otp2 需要同步的第二个动态口令
* otp2len 需要同步的第二个动态口令长度, 通常是6
* currsucc 认证成功后的相对UTC Epoch秒数 //同步成功后应写入数据库,供下次调用。
* currdft 认证成功后的当前漂移次数 //同步成功后应写入数据库,供下次调用。
*
* return : 0 - 成功, 其他值为错误.
*/
4.点击认证按钮时,执行的逻辑:
string authkey = ""; //秘钥
UInt64 t = (ulong)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; //时间戳
UInt64 t0 = 0; //起始参考时间相对UTC
uint x = 60; //口令变化周期,默认60秒
int drift = 0; //上次漂移值
int authwnd = 20; //认证范围
UInt64 lastsucc = 0; //上次成功值
string opt = tbCode.Text; //用户输入的口令
int optlen = 6; //口令长度
UInt64 currsucc = 0; //默认的成功值
int currdft = 0; // 默认的漂移值
//首先验证用户登录,登录成功后将用户信息放到userModel中
Model.TokenModel tokenModel = GetTokenModel(userModel.token_sn); //根据用户表中的令牌序列号查询令牌表中的内容
authkey = tokenModel.token_authkey;
lastsucc = tokenModel.token_currsucc;
drift = tokenModel.token_currdft;
int ret = ET_CheckPwdz201(authkey, t, t0, x, drift, authwnd, lastsucc, opt, optlen, ref currsucc, ref currdft);
if(ret == 0)
{
更新数据库("update 令牌表 set token_currsucc='" + currsucc + "',token_currdft='" + currdft + "' where 令牌序列号='" + tokenModel.令牌序列号 + "'"); //认证成功时需回写该令牌的成功值和漂移值
Response.Write("认证成功!(成功值:" + currsucc + ",漂移值:" + currdft + "]");
}
else
{
Response.Write("认证失败,错误码:" + ret);
}
返回值说明:
#define OTP_SUCCESS (0x00000000L) //操作成功
#define OTP_ERR_INVALID_PARAMETER (0x00000001L) //参数无效
#define OTP_ERR_CHECK_PWD (0x00000002L //认证失败
#define OTP_ERR_SYN_PWD (0x00000003L) //同步失败
#define OTP_ERR_REPLAY (0x000000004) //动态口令被重放