认证过程为,服务端生成一个随机数(认证原文),CA服务器中使用用户的证书里面的公钥进行加密这个随机数,然后用户收到这个加密后的随机数后使用usbkey里面的私钥来解密出认证原文,然后将原文发送到服务端进行比对,如果和开始生成的原文一致,则用户的身份是合法的。
这里我写了一个WebService来生成原文并保存到数据库。然后通过插件来提取用户证书公钥加密。
public class CALogic : WebService
{
protected static NLog.Logger Log
{
get { return NLog.LogManager.GetCurrentClassLogger(); }
}
/// <summary>
/// 证书验证,如果origncode为空 则返回认证原文
/// 否则对比origncode和数据库中的原文,
/// 客户端 验证需要调用两次Verify
/// 1.获取认证原文 原文= Verify(编号,NULL)
/// 2.客户端解密第一步得到的 原文
/// 认证结果=Verify(编号,原文)
/// </summary>
[WebMethod]
public string Verify(string username, string origncode)
{
var session = CASessionFactory.CurrentSession();
try
{
var user = session.QueryOver<Users>()
.Where(o => o.UserName == username).Take(1)
.SingleOrDefault();
if (null == user)
{
return "用户不存在!";
}
var cert = session.QueryOver<CaCertificate>()
.Where(o => o.UID == user.UID)
.Take(1).SingleOrDefault();
if (cert == null)
{
return "未找到用户证书";
}
if (cert.EndTime < DateTime.Now)
{
return "用户证书已过期!";
}
switch (cert.State)
{
case CertState.Freeze:
return "用户证书已冻结";
case CertState.Abort:
return "用户证书已吊销";
case CertState.Approving:
return "用户证书待审批";
}
//返回认证原文
if (string.IsNullOrEmpty(origncode))
{
var result= CaOperator.NewOriginalCode(session, cert);
return result;
}
//验证认证原文
return CaOperator.VerifyOriginalCode(session, cert.UID, origncode) ? "认证成功" : "认证失败";
}
catch (Exception e)
{
Log.Error(e);
return "认证异常";
}
finally
{
session.Close();
}
}
}