背景:

甲方爸爸们越来越重视系统的安全性,我方系统本来采用账户+密码形式登录的(其他也支持)。现在要求登录必须对接专门的密评公司,第一阶段为采用u_key也就是插优盘登录。后续考虑再做其他形式。

一开始不了解这块东西,觉得挺难的。等拿到密评公司的相关文档后,基于目前系统进行改造。整个过程还算顺利,中间由于不清楚一些接口的定义,和三方的人员沟通过几次。

要的效果:

系统登陆时,插入ca锁,输入ca密码,完成校验后即可登录成功。

实现过程:

UKEY证书登录的流程为:

  1. 客户端从服务端获取随机数并生成签名值(raw裸签名)
  2. 将签名值数据传给业务服务端
  3. 业务服务端将讲客户端传过来的签名数据调用密码服务接口验签
  4. 返回验签结果,根据验签结果运行客户端登陆

设计:
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);@Overridepublic 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);//获取tokenpublic 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;}//获取认证headerpublic 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;}
}

对接湖南CA使用U_KEY登录相关推荐

  1. Zabbix 对接 LDAP 实现用户统一登录的方法

    需求 某公司环境是基于AD域来批量管理域用户的,zabbix监控平台上又要创建账号,这样非常麻烦,也不利于账号的管理,所以为了集中管理,想通过zabbix对接公司AD域用户,实现用户认证统一登录. 环 ...

  2. 华为防火墙配置SSL+自签CA证书挑战登录

    HW USG部署SSL+CA证书登录 前言 了解证书 自签证书 服务器配置 客户端配置 客户端登录 前言 关于证书,涉及作者的知识盲区,本人仅根据自己的理解编写,仅供参考! 了解证书 公钥CA:理解为 ...

  3. java对接微信小程序(登录获取用户信息)

    需求说明: 用户通过小程序登录,进入到平台系统,进行各功能操作: 解决方案: 首先通过对接小程序,用户通过小程序登录及授权获取用户信息,后端调用接口获取微信用户信息,进行保存到数据库,然后返回toke ...

  4. Vue 前端对接第三方平台扫码登录(Oauth2)

    本方式是用 Oauth2 的方式实现扫码登录的,其中省略了不少不重要的代码 1.编写页面样式,设置扫码链接入口 1.页面样式不多说,参考一下: <el-dropdown><span ...

  5. java对接ntlm,httpclient 实现自动登录NTLM 域验证(sso) .

    最近一个项目拿到客户那运行不了.原来我的这个项目要和另一个系统通过http的接口进行通讯.但在客户的生产环境中,那套系统将web应用的登录和Windows Domain的登录结合,做了一个sso单点登 ...

  6. PHP原生对接QQ互联/实现QQ登录,SDK2.1版本/超级详细!

    在目前在大部分网站中都会接入QQ登录或者微信登录,目前QQ互联的接入门槛是比较低的,官方的前提是必须备案网站!!如果网站没有备案请某宝自行搜索一下其他方法.用QQ登录接口,首先要到QQ互联完善开发者认 ...

  7. 阿里云一键登录(对接移动端) PHP

    阿里云一键登录(对接移动端) PHP 一键登录的流程 一键登录的好处 极速稳定 无需发送短信验证码,避免出现通道拥堵,短信延迟等不稳定因素. 节约短信成本 一键登录比短信验证成本降低了20%以上,而且 ...

  8. JAVA Spring Security对接QQ快速登录(web应用)

    阅读此文需要对Security有大概的了解,了解其运行流程 security对接QQ互联jssdk快速登录 前端使用的是vue.js 1.首先在QQ互联申请一个应用,得到appid和设置好回调地址 2 ...

  9. 微信qq一键登录php代码6,Laravel6实现第三方 微信登录

    目前很多的网站中都会存在很多的交互功能,从而降低用户的操作难度,特此带来微信的第三方登录的项目实战功能开发.对于本实例中的开发内容,就不在使用原生的内容,而是直接使用别人写好的封装的类库. 1. 安装 ...

  10. 快递电子面单批量打印接口对接demo-JAVA

    目前有三种方式对接电子面单: 1.快递公司:各家快递公司逐一对接接口 2.菜鸟:支持常用15家快递电子面单打印 3.快递鸟:仅对接一次,支持常用30多家主流快递电子面单打印 目前也是支持批量打印电子面 ...

最新文章

  1. Linux基础命令---znew
  2. Google Guava Collections 使用介绍
  3. 个人网站建设要避开这些“通病”
  4. 8.2 TensorFlow实现KNN与TensorFlow中的损失函数,优化函数
  5. Linux——进程控制(总结)
  6. HTML特殊字符大全2
  7. 256种编程语言大荟萃
  8. uva 10037——Bridge
  9. 关于微信浏览器H5 React,Vue工程化项目input无法自动聚焦疑难杂症排查
  10. ccie 与 java,上海ccie脚踏实地,java常量
  11. python 模拟登录验证码_Python模拟登陆 —— 征服验证码 3 CSDN
  12. cocos2d(粒子效果编辑器)
  13. 狂砸250多亿!亚马逊花了7年时间,造了一个让你自愿加班到死的办公室!
  14. 学习C语言的入门程序
  15. Java——猜数字游戏
  16. 携程数据开发2022留用实习面试
  17. 4.9冰箱的温度c语言,话说夏天冰箱温度调到多少度为最佳?
  18. 阿里云服务器ICP备案流程概述
  19. C#窗体程序使用SQL数据库
  20. python format函数 日期_Python-日期格式化

热门文章

  1. 毕业两年半,星光不问赶路人,时光不负有心人
  2. 非科班无实习如何入职腾讯?后台开发岗个人校招学习路线分享!
  3. 云教室管理平台 部署手册(无图)
  4. 网站常用色彩表(网络搜集整理)
  5. 天天说大数据但不知怎么用?读完这篇你就懂了
  6. ERstudio导入mysql脚本生成rtf文档
  7. 电子计算机与媒体阅读答案,电子计算机与多媒体课课练.docx
  8. excel函数去重_excel去重函数
  9. 筛选中很容易粘贴到被隐藏部分_Excel中复制(或粘贴)含有隐藏单元格的区域时如何只对可见单元格进行操作...
  10. 慧荣SM2258XT-主板CE跳线Toggle土狗跳线合集整理(持续更新)