对接湖南CA使用U_KEY登录
ca、使用usbKey登录
·
背景:
甲方爸爸们越来越重视系统的安全性,我方系统本来采用账户+密码形式登录的(其他也支持)。现在要求登录必须对接专门的密评公司,第一阶段为采用u_key也就是插优盘登录。后续考虑再做其他形式。
一开始不了解这块东西,觉得挺难的。等拿到密评公司的相关文档后,基于目前系统进行改造。整个过程还算顺利,中间由于不清楚一些接口的定义,和三方的人员沟通过几次。
要的效果:
系统登陆时,插入ca锁,输入ca密码,完成校验后即可登录成功。
实现过程:
UKEY证书登录的流程为:
- 客户端从服务端获取随机数并生成签名值(raw裸签名)
- 将签名值数据传给业务服务端
- 业务服务端将讲客户端传过来的签名数据调用密码服务接口验签
- 返回验签结果,根据验签结果运行客户端登陆
设计:
1、用户信息保存在我方系统中,在用户管理页面,为用户关联UKEY锁。
下载ca锁驱动并安装,插入锁,读取锁的sn序列号,与用户信息绑定,保存在数据库中。sn序列号和用户一对一关系。(前端进行读取,相关操作及代码三方提供有参考文档)
2、改造登录 插入ca锁,输入锁的密码后进行登录。
2.1前端进行ca的基本校验操作,均可参考三方文档实现。对ca密码、序列号的校验。无误后根据密码+序列号+随机数(用于加密的原文),生成签名数据certData以及签名证书ceertSign,然后将签名、密码、certData、certSign传到后端进行处理。
2.2后端基于公司的现有的框架做的处理,相当于对登录做了拦截。
后端获取到传递的参数,进行数据的校验,通过后根据 序列号sn查询user表,查询当前锁是否关联用户信息,否则结束并提示。是则进行验签操作。
验签有专门的接口,只需根据接口文档进行调用。验签若成功,则可以让当前用户登录成功,反之则失败。
相关代码展示在后面:
前端相关代码
function check(loadtype) {
debugger;
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
var devList = "";
var devName = "";
var signData = "";
var signCert = "";
if (1 == loadtype) {
username = checkUsbKey();
password = document.getElementById("passwordca").value;
if (username==false){
return false;
}
if (password == "") {
epoint.alert("CA密码不能为空");
return false;
}
//验证
devList = mToken.Hunca_GetUserListGN(); //枚举Ukey,获取证书G项信息列表
if(null == devList){
alert(mToken.Hunca_GetLastError());
return false;
}
devName = devList[0];
userName = mToken.Hunca_userNameGNToUserName(devName);
if(!mToken.Hunca_PKCS1(password,userName,password)){
alert(mToken.Hunca_GetLastError());
return false;
}
//获取签名结果
signData = mToken.Hunca_GetSignData();
//签名证书
signCert = mToken.Hunca_GetSignCert();
} else {
if (username == "") {
epoint.alert("用户名不能为空");
return false;
}
if (password == "") {
epoint.alert("密码不能为空");
return false;
}
}
username = epoint.encodeUtf8(username);
username = sm2Encrypt(username, sm2PubKey, 0);
password = epoint.encodeUtf8(password);
password = sm2Encrypt(password, sm2PubKey, 0);
var verifycode = "";
<!-- 如果需要验证码,则打开下面这段注释 -->
<!-- begin -->
var codeinput = $.trim($codeinput.val());
/* if (!codeinput) {
result = false;
epoint.alert('验证码不能为空!');
return false;
} */
if (!$("#verifycode-box").is(":hidden")) {
if (!codeinput) {
result = false;
epoint.showTips('验证码不能为空!', {
state : 'warning'
});
return false;
}
}
var codedata = $unvisualcode.val();
verifycode = codeinput + '#' + codedata;
<!-- end -->
userName_securityverification=username;
passWord_securityverification=password;
verifycode_securityverification=verifycode;
rememberMe_securityverification='';
loginType_securityverification=loadtype;
sign_securityverification = signData;
// 登录
if(loadtype=='1'){
epoint.execute('loginaction.cacustomlogin', '', [ username, password,
loadtype, signData, signCert ], checkMultipleLogin);
}else {
epoint.execute('loginaction.login', '', [ username, password,
loadtype, '', verifycode ], checkMultipleLogin);
}
return true;
}
var mToken = new hunca_mToken_core();
function checkUsbKey() {
//第一步:获取证书名称
var devList = "";
var selectDev = null;
//枚举Ukey,获取证书G项信息列表
devList = mToken.Hunca_GetUserListGN();
if(null == devList){
epoint.showTips(mToken.Hunca_GetLastError(),{state : 'warning'});
return false;
}
selectDev = devList[0];
//第二步 获取证书序号
var userNameGN= null,userName = "";
var caSN = "";
userNameGN = selectDev;
userName = mToken.Hunca_userNameGNToUserName(userNameGN); //将证书G项信息转化为证书名称
if(!mToken.Hunca_DealCertInfo(userName)){
epoint.showTips(mToken.Hunca_GetLastError(),{state : 'warning'});
return false;
}
caSN = mToken.Hunca_GetSignCertSn();
// document.getElementById("ca_sn").value = caSN;
return caSN;
}
后台代码:
/**
* @author lqfeng
* @desc 个性登录流程接口
* @date 2022/7/19 11:32
*/
public class CqCaCustomIdentityBuilder extends FrametIdentityBuilder {
private static final Logger log = LoggerFactory.getLogger(CqCaCustomIdentityBuilder.class);
@Override
public AuthenticationToken build(ServletRequest request, ServletResponse response) {
AuthenticationToken authenticationToken = null;
CqCaCustomIdentityService caCustomIdentityService = new CqCaCustomIdentityService();
String username = "";
String password = "";
String loadType = "0";
String signData = "";
String signCert = "";
boolean rememberMe = false;
String multiParam = "";
FrameUser user = null;
log.info("开始执行自定义build");
//1、获取传递的参数
String cmdparams = WebUtils.getCleanParam(request, "cmdParams");
if (StringUtil.isNotBlank(cmdparams)) {
//参数格式处理
if (cmdparams.startsWith("[")) {
cmdparams = cmdparams.substring(1);
}
if (cmdparams.endsWith("]")) {
cmdparams = cmdparams.substring(0, cmdparams.length() - 1);
}
//转为参数数组
String[] arr = cmdparams.split(",");
log.info("前端传递的参数为:{}",arr);
username = this.format(arr[0]);
password = this.format(arr[1]);
if (arr.length > 2) {
loadType = this.format(arr[2]);
}
if (arr.length > 3) {
signData = this.format(arr[3]);
}
if (arr.length > 4) {
signCert = this.format(arr[4]);
}
}
//2、根据loadType 类型,判断是否走个性化ca登录处理
if (loadType.equals("1")){
log.info("当前为ca登录。。。");
//2.1获取CA密码 解密
username = this.decode(username);
password = this.decode(password);
log.debug("解析后的sn为{},password为:{}",username,password);
//2.2用户名或密码不能为空
if (StringUtil.isBlank(username)||StringUtil.isBlank(password)){
return errorToken("用户名或密码不能为空", response);
}
//2.4根据sn判断ca锁是否绑定用户
user = caCustomIdentityService.isBindUser(username);
if (user==null||StringUtil.isBlank(user.getLoginId())){
//当前CA锁未绑定用户
return errorToken("当前CA锁未绑定用户", response);
}
//
//2.3 验签判断
Boolean certVaild = caCustomIdentityService.judgetSignVaild(signData,signCert,password);
if (!certVaild){
return errorToken("签名验证失败,请确认uKey试过正确", response);
}
}
Map<String, String> extendMap = new HashMap();
Identity identity = createCommonToken(user.getLoginId(),user.getPassword(),"1",request,response,"cacustomlogin");
return identity;
}
private AuthenticationToken errorToken(String msg, ServletResponse response)
{
Map params = new HashMap();
params.put("systemMessages", msg);
addCallBackMessageWithAjax(params, (HttpServletResponse)response);
return null;
}
}
//raw验签
public Boolean judgetSignVaild(String signData,String signCert,String password) {
String url = new FrameConfigService9().getFrameConfigValueByNameWithDefault("SIGN_VERIFY_RAW_URL", CaConstant.SIGN_VERIFY_RAW_URL);
Map tokenHeader = CertUile.getTokenHeader();
Map params = new HashMap<>();
String appId = new FrameConfigService9().getFrameConfigValueByNameWithDefault("CA_appId", CaConstant.CA_APP_ID);
String password1= Base64.getEncoder().encodeToString(password.getBytes());
String password2= Base64.getEncoder().encodeToString(password1.getBytes());
//原文
params.put("plainText",password2);
//签名结果
params.put("signedText", signData);
//签名证书
params.put("cert", signCert);
//时间戳
params.put("tsaText", System.currentTimeMillis());
//算法
params.put("digestAlg", null);
//密钥标识
params.put("keyId", appId);
String s = JsonUtil.objectToJson(params);
log.info("body参数为:{}",s);
String result = HttpUtil.doHttp(url, (Map<String, String>) tokenHeader, s, "POST", 2);
log.info("raw验签接口返回结果为:{}",result);
if (result.contains("成功")){
return true;
}
return false;
}
工具类
/**
* @author lqfeng
* @desc 密评util
* @date 2022/7/20 11:22
*/
public class CertUile {
private static final Logger log = LoggerFactory.getLogger(CertUile.class);
//获取token
public static String getToken() {
String token = "";
String hmac = "";
//获取参数值,可配置为系统参数
String appId = new FrameConfigService9().getFrameConfigValueByNameWithDefault("CA_appId", CaConstant.CA_APP_ID);
String secretKey = new FrameConfigService9().getFrameConfigValueByNameWithDefault("CA_appSecretKey", CaConstant.CA_APP_SECRETKEY);
String random = String.valueOf(System.currentTimeMillis());
String plainText = appId + "||" + random + "||" + secretKey;
byte[] hmacbyte = HmacUtils.encodeHmacSHA256(plainText.getBytes(), secretKey.getBytes());
hmac = Base64.getEncoder().encodeToString(hmacbyte);
log.info("HmacSHA256加密后的hmac值为:{}",hmac);
Map headerMap = new HashMap<>();
headerMap.put("appId", appId);
Map paramMap = new HashMap<>();
paramMap.put("random",random );
paramMap.put("hmac",hmac );
String jsonParams = JsonUtil.objectToJson(paramMap);
log.info("请求参数header:{},bodyParam:{}",headerMap,paramMap);
//请求token接口
String result = HttpUtil.doHttp(CaConstant.APP_TOKEN_URL, (Map<String, String>) headerMap, jsonParams, "POST", 2);
if (result.contains("成功")){
Map<String, Object> map = JsonUtil.jsonToMap(result);
Map<String, String> data = (Map<String, String>) map.get("data");
token = data.get("token");
log.info("获取到的token值为:{}",token);
}
return token;
}
//获取认证header
public static Map getTokenHeader(){
String appId = new FrameConfigService9().getFrameConfigValueByNameWithDefault("CA_appId", CaConstant.CA_APP_ID);
String token = getToken();
String random = String.valueOf(System.currentTimeMillis());
String nonce = UUID.randomUUID().toString().replaceAll("-", "");
Map headerMap = new HashMap<>();
headerMap.put("appId",appId);
headerMap.put("token",token);
headerMap.put("random",random);
headerMap.put("nonce",nonce);
return headerMap;
}
}
更多推荐
已为社区贡献1条内容
所有评论(0)