工资查询

master
damac 2026-03-28 18:29:47 +08:00
parent 728775b21a
commit 6eac139ec7
16 changed files with 1048 additions and 47 deletions

View File

@ -2,11 +2,18 @@ package com.ruans.web.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ruans.common.core.domain.model.LoginUser;
import com.ruans.common.core.utils.*;
import com.ruans.system.domain.SysUser;
import com.ruans.system.domain.vo.SysUserVo;
import com.ruans.system.mapper.SysUserMapper;
import com.ruans.system.service.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -31,10 +38,6 @@ import com.ruans.common.tenant.helper.TenantHelper;
import com.ruans.system.domain.bo.SysTenantBo;
import com.ruans.system.domain.vo.SysClientVo;
import com.ruans.system.domain.vo.SysTenantVo;
import com.ruans.system.service.ISysClientService;
import com.ruans.system.service.ISysConfigService;
import com.ruans.system.service.ISysSocialService;
import com.ruans.system.service.ISysTenantService;
import com.ruans.web.domain.vo.LoginTenantVo;
import com.ruans.web.domain.vo.LoginVo;
import com.ruans.web.domain.vo.TenantListVo;
@ -73,6 +76,9 @@ public class AuthController {
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
private final PKIAuthService pkiAuthService;
private final ISysUserService userService;
private final String PC_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
/**
*
@ -112,6 +118,40 @@ public class AuthController {
return R.ok(loginVo);
}
@SaIgnore
@PostMapping("/pkiLogin")
public R pkiLogin(@RequestBody Map map) throws Exception {
String signedData = (String) map.get("signedData");
String originalNum = (String) map.get("originalNum");
String userData = pkiAuthService.pkiAuth(signedData, originalNum);
String usermg = userData.split(",")[0];
String sfz = usermg.split("\\s+")[1];
SysUserVo user = userService.selectUserByIdCard(sfz);
// SysUserVo vo = BeanUtil.toBean(user, SysUserVo.class);
if (null != user && "0".equals(user.getStatus())) {
SysClientVo client = clientService.queryByClientId(PC_CLIENT_ID);
SaLoginModel model = new SaLoginModel();
model.setDevice(client.getDeviceType());
// 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
// 例如: 后台用户30分钟过期 app用户1天过期
model.setTimeout(client.getTimeout());
model.setActiveTimeout(client.getActiveTimeout());
model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId());
LoginUser loginUser = loginService.buildLoginUser(user);
LoginHelper.login(loginUser,model);
Map<String, Object> ajax = new HashMap<String, Object>();
ajax.put("access_token", StpUtil.getTokenValue());
return R.ok(ajax);
}
return R.fail("用户不在本系统内");
}
@SaIgnore
@RequestMapping("/generateOriginalNum")
public R generateOriginalNum() {
return R.ok("操作成功", pkiAuthService.generateOriginalNum());
}
/**
* URL
*

View File

@ -277,8 +277,20 @@ websocket:
--- # warm-flow工作流配置
warm-flow:
# 是否开启工作流默认true
enabled: true
enabled: false
# 是否开启设计器ui
ui: true
ui: false
# 默认Authorization如果有多个token用逗号分隔
token-name: ${sa-token.token-name},clientid
#pki认证信息
pki:
#网关认证服务地址
authUrl: http://53.136.1.36:6180/MessageService
#AppId
appId: 08028340800
#应用服务器地址
remoteAddr: http://53.64.16.201:9528
#是否检查访问控制状态。false表示不检查当设置为“false”时网关不做任何处理
#响应报文中也不会有任何相关信息。true表示检查当设置为“true”时网关检查用户是否允许访问此应用并在报文中给出相应的信息。
accessControl: true

View File

@ -94,6 +94,17 @@
<artifactId>ip2region</artifactId>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,102 @@
package com.ruans.common.core.utils;
import java.util.Map;
/**
* <p>description: </p>
*
* @author chenle
* @date 2020/5/6 21:01
*/
public class AuthResult {
// 认证成功标记
private boolean isSuccess;
// 错误编码
private String errCode;
// 错误描述
private String errDesc;
// 认证结果-认证属性
//private Map<String[],String> certAttributeNodeMap;
private Map certAttributeNodeMap;
// 认证结果-UMS
//private Map<String[],String> umsAttributeNodeMap;
private Map umsAttributeNodeMap;
// 认证结果-PMS
//private Map<String[],String> pmsAttributeNodeMap;
private Map pmsAttributeNodeMap;
// 认证结果-自定义属性
private Map customAttributeNodeMap;
// 认证结果-自定义属性
private String customAttrsElement;
// 认证结果-访问控制
private String accessControlResult;
public boolean isSuccess() {
return isSuccess;
}
private void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
public String getErrCode() {
return errCode;
}
private void setErrCode(String errCode) {
this.errCode = errCode;
}
public String getErrDesc() {
return errDesc;
}
private void setErrDesc(String errDesc) {
this.errDesc = errDesc;
}
public Map getCertAttributeNodeMap() {
return certAttributeNodeMap;
}
public void setCertAttributeNodeMap(Map certAttributeNodeMap) {
this.certAttributeNodeMap = certAttributeNodeMap;
}
public Map getUmsAttributeNodeMap() {
return umsAttributeNodeMap;
}
public void setUmsAttributeNodeMap(Map umsAttributeNodeMap) {
this.umsAttributeNodeMap = umsAttributeNodeMap;
}
public Map getPmsAttributeNodeMap() {
return pmsAttributeNodeMap;
}
public void setPmsAttributeNodeMap(Map pmsAttributeNodeMap) {
this.pmsAttributeNodeMap = pmsAttributeNodeMap;
}
public String getCustomAttrsElement() {
return customAttrsElement;
}
public void setCustomAttrsElement(String customAttrsElement) {
this.customAttrsElement = customAttrsElement;
}
public Map getCustomAttributeNodeMap() {
return customAttributeNodeMap;
}
public void setCustomAttributeNodeMap(Map customAttributeNodeMap) {
this.customAttributeNodeMap = customAttributeNodeMap;
}
public String getAccessControlResult() {
return accessControlResult;
}
public void setAccessControlResult(String accessControlResult) {
this.accessControlResult = accessControlResult;
}
@Override
public String toString() {
return super.toString();
}
}

View File

@ -0,0 +1,215 @@
package com.ruans.common.core.utils;
/**
* <p>description: </p>
*
* @author chenle
* @date 2020/5/6 17:35
*/
public class PKIUtils {
/**
*
* @return
*/
public static String generateOriginalNum(){
String num = "1234567890abcdefghijklmnopqrstopqrstuvwxyz";
int size = 6;
char[] charArray = num.toCharArray();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < size; i++) {
sb.append(charArray[((int) (Math.random() * 10000) % charArray.length)]);
}
return sb.toString();
}
/**
*
* @author weichang_ding
*
*/
public static class CommonConstant{
// 报文根结点
public static final String MSG_ROOT = "message";
// 报文头结点
public static final String MSG_HEAD = "head";
// 报文体结点
public static final String MSG_BODY = "body";
// 服务版本号
public static final String MSG_VSERSION = "version";
// 服务版本值
public static final String MSG_VSERSION_VALUE_10 = "1.0";
public static final String MSG_VSERSION_VALUE_11 = "1.1";
// 服务类型
public static final String MSG_SERVICE_TYPE = "serviceType";
// 报文体 应用ID
public static final String MSG_APPID = "appId";
// 响应报文状态
public static final String MSG_MESSAGE_STATE = "messageState";
// 错误代码
public static final String MSG_MESSAGE_CODE = "messageCode";
// 错误描述
public static final String MSG_MESSAGE_DESC = "messageDesc";
// 认证原文
public static final String MSG_ORIGINAL = "original";
}
/**
*
* @author weichang_ding
*
*/
static class RandomConstant{
// 服务类型值
public static final String MSG_SERVICE_TYPE_VALUE = "OriginalService";
}
/**
*
* @author weichang_ding
*
*/
public static class AuthConstant{
// 服务类型值
public static final String MSG_SERVICE_TYPE_VALUE = "AuthenService";
// 报文体 认证方式
public static final String MSG_AUTH_MODE = "authMode";
// 报文体 证书认证方式
public static final String MSG_AUTH_MODE_CERT_VALUE = "cert";
// 报文体 口令认证方式
public static final String MSG_AUTH_MODE_PASSWORD_VALUE = "password";
// 报文体 二维码认证方式
public static final String MSG_AUTH_MODE_QRCODE_VALUE = "qrcode";
// 报文体 属性集
public static final String MSG_ATTRIBUTES = "attributes";
// 报文体 自定义属性集
public static final String MSG_CUSTOM_ATTRIBUTES = "customAttributes";
// 报文体 属性
public static final String MSG_ATTRIBUTE = "attr";
// 报文体 属性名
public static final String MSG_NAME = "name";
// 报文父级节点
public static final String MSG_PARENT_NAME = "parentName";
// 报文体 属性空间
public static final String MSG_NAMESPACE = "namespace";
// 访问控制
public static final String MSG_ACCESS_CONTROL = "accessControl";
// 访问控制 ture
public static final String MSG_ACCESS_CONTROL_TRUE = "true";
// 访问控制 false
public static final String MSG_ACCESS_CONTROL_FALSE = "false";
// 报文体 认证结点
public static final String MSG_AUTH = "authen";
// 报文体 认证凭据
public static final String MSG_AUTHCREDENTIAL = "authCredential";
// 报文体 客户端结点
public static final String MSG_CLIENT_INFO = "clientInfo";
// 报文体 公钥证书
public static final String MSG_CERT_INFO = "certInfo";
// 报文体 客户端结点
public static final String MSG_CLIENT_IP = "clientIP";
// 报文体 detach认证请求包
public static final String MSG_DETACH = "detach";
// 报文体 证书类型PM 证书为PM
public static final String MSG_CERTTYPE = "certType";
// 报文体 用户名
public static final String MSG_USERNAME = "username";
// 报文体 口令
public static final String MSG_PASSWORD = "password";
// 报文体 Token
public static final String MSG_TOKEN = "token";
// QRCode
public static final String MSG_QRCODE = "QRCode";
// 报文体 属性类型
public static final String MSG_ATTRIBUTE_TYPE = "attributeType";
// 指定属性 portion
public static final String MSG_ATTRIBUTE_TYPE_PORTION = "portion";
// 指定属性 all
public static final String MSG_ATTRIBUTE_TYPE_ALL = "all";
// 指定属性列表控制项 attrType
public static final String MSG_ATTR_TYPE = "attrType";
// 报文体 认证结果集
public static final String MSG_AUTH_RESULT_SET = "authResultSet";
// 报文体 认证结果
public static final String MSG_AUTH_RESULT = "authResult";
// 报文体 认证结果状态
public static final String MSG_SUCCESS = "success";
// 报文体 认证错误码
public static final String MSG_AUTH_MESSSAGE_CODE = "authMessageCode";
// 报文体 认证错误描述
public static final String MSG_AUTH_MESSSAGE_DESC = "authMessageDesc";
// 二维码随机数
public static final String KEY_JIT_QRCODE = "jit_qrcode";
// session中原文
public static final String KEY_ORIGINAL_DATA = "original_data";
// 客户端返回的认证原文request中原文
public static final String KEY_ORIGINAL = "original";
// 签名结果
public static final String KEY_SIGNED_DATA = "signed_data";
// namespace 证书信息
public static final String KEY_NAMESPACE_CINAS = "http://www.jit.com.cn/cinas/ias/ns/saml/saml11/X.509";
// namespace ums信息
public static final String KEY_NAMESPACE_UMS = "http://www.jit.com.cn/ums/ns/user";
// namespace pms信息
public static final String KEY_NAMESPACE_PMS = "http://www.jit.com.cn/pmi/pms";
// namespace 自定义信息
public static final String KEY_NAMESPACE_CUSTOM = "http://www.jit.com.cn/gw/custom/attribute";
}
/**
*
* @author weichang_ding
*
*/
}

View File

@ -3,8 +3,10 @@ package com.ruans.biz.controller;
import java.util.ArrayList;
import java.util.List;
import cn.dev33.satoken.stp.StpUtil;
import com.ruans.common.excel.core.ExcelResult;
import com.ruans.biz.domain.vo.BizSalaryImportVo;
import com.ruans.common.satoken.utils.LoginHelper;
import com.ruans.system.listener.BizSalaryImportListener;
import com.ruans.system.listener.SysUserImportListener;
import lombok.RequiredArgsConstructor;
@ -49,6 +51,10 @@ public class BizSalaryController extends BaseController {
@SaCheckPermission("biz:salary:list")
@GetMapping("/list")
public TableDataInfo<BizSalaryVo> list(BizSalaryBo bo, PageQuery pageQuery) {
if (!StpUtil.hasRoleOr("manager", "superadmin")){
bo.setUserId(LoginHelper.getUserId());
}
return bizSalaryService.queryPageList(bo, pageQuery);
}
@ -71,7 +77,7 @@ public class BizSalaryController extends BaseController {
*/
@PostMapping("/importTemplate")
public void importTemplate(HttpServletResponse response) {
ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", BizSalaryImportVo.class, response);
ExcelUtil.exportExcel(new ArrayList<>(), "工资明细", BizSalaryImportVo.class, response);
}
/**
@ -81,6 +87,10 @@ public class BizSalaryController extends BaseController {
@Log(title = "工资明细", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BizSalaryBo bo, HttpServletResponse response) {
if (!StpUtil.hasRoleOr("manager", "superadmin") || bo.getUserId().equals(-1)){
bo.setUserId(LoginHelper.getUserId());
}
List<BizSalaryVo> list = bizSalaryService.queryList(bo);
ExcelUtil.exportExcel(list, "工资明细", BizSalaryVo.class, response);
}

View File

@ -70,7 +70,7 @@ public class BizSalary extends BaseEntity {
/**
*
*/
private String yearMonth;
private String salaryYearMonth;
/**
*

View File

@ -68,7 +68,7 @@ public class BizSalaryBo extends BaseEntity {
/**
*
*/
private String yearMonth;
private String salaryYearMonth;
/**
*

View File

@ -1,6 +1,8 @@
package com.ruans.biz.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.ruans.common.excel.annotation.ExcelDictFormat;
import com.ruans.common.excel.convert.ExcelDictConvert;
import lombok.Data;
@ -26,6 +28,7 @@ public class BizSalaryImportVo implements Serializable {
/**
* ID
*/
@ExcelIgnore
private Long id;
/**
@ -37,11 +40,13 @@ public class BizSalaryImportVo implements Serializable {
/**
* ID
*/
@ExcelIgnore
private Long userId;
/**
*
*/
@ExcelIgnore
private String policeNo;
/**
@ -53,39 +58,46 @@ public class BizSalaryImportVo implements Serializable {
/**
*
*/
@ColumnWidth(18)
@ExcelProperty(value = "身份证号")
private String idcard;
/**
*
*/
@ColumnWidth(20)
@ExcelProperty(value = "银行卡号")
private String bankCard;
/**
* ID
*/
@ExcelIgnore
private String deptId;
/**
*
*/
@ExcelIgnore
private String deptName;
/**
*
*/
@ExcelProperty(value = "月份")
private String yearMonth;
@ColumnWidth(10)
@ExcelProperty(value = "月份", index = 0)
private String salaryYearMonth;
/**
*
*/
@ExcelIgnore
private Long salaryYear;
/**
*
*/
@ExcelIgnore
private Long salaryMonth;
/**
@ -187,36 +199,42 @@ public class BizSalaryImportVo implements Serializable {
/**
*
*/
@ColumnWidth(8)
@ExcelProperty(value = "增发")
private Long increasePay;
/**
*
*/
@ColumnWidth(8)
@ExcelProperty(value = "减发")
private Long reducePay;
/**
*
*/
@ColumnWidth(8)
@ExcelProperty(value = "应发")
private Long totalPay;
/**
*
*/
@ColumnWidth(8)
@ExcelProperty(value = "实发")
private Long actualSalary;
/**
*
*/
@ColumnWidth(25)
@ExcelProperty(value = "备注")
private String remark;
/**
* ID
*/
@ExcelIgnore
private Long createUserId;
}

View File

@ -81,7 +81,7 @@ public class BizSalaryVo implements Serializable {
*
*/
@ExcelProperty(value = "月份")
private String yearMonth;
private String salaryYearMonth;
/**
*

View File

@ -28,10 +28,10 @@ public interface IBizSalaryService {
*
*
* @param idCard
* @param yearMonth
* @param salaryYearMonth
* @return
*/
BizSalaryVo selectSalaryByIdCardAndMouth(String idCard, String yearMonth);
BizSalaryVo selectSalaryByIdCardAndMouth(String idCard, String salaryYearMonth);
/**
*

View File

@ -47,12 +47,12 @@ public class BizSalaryServiceImpl implements IBizSalaryService {
*
*
* @param idcard
* @param yearMonth
* @param salaryYearMonth
* @return
*/
@Override
public BizSalaryVo selectSalaryByIdCardAndMouth(String idcard, String yearMonth){
return baseMapper.selectVoOne(new LambdaQueryWrapper<BizSalary>().eq(BizSalary::getIdcard, idcard).eq(BizSalary::getYearMonth, yearMonth));
public BizSalaryVo selectSalaryByIdCardAndMouth(String idcard, String salaryYearMonth){
return baseMapper.selectVoOne(new LambdaQueryWrapper<BizSalary>().eq(BizSalary::getIdcard, idcard).eq(BizSalary::getSalaryYearMonth, salaryYearMonth));
}
/**
@ -84,7 +84,7 @@ public class BizSalaryServiceImpl implements IBizSalaryService {
private LambdaQueryWrapper<BizSalary> buildQueryWrapper(BizSalaryBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<BizSalary> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(BizSalary::getId);
lqw.orderByDesc(BizSalary::getSalaryYearMonth);
lqw.eq(StringUtils.isNotBlank(bo.getSalaryType()), BizSalary::getSalaryType, bo.getSalaryType());
lqw.eq(bo.getUserId() != null, BizSalary::getUserId, bo.getUserId());
lqw.eq(StringUtils.isNotBlank(bo.getPoliceNo()), BizSalary::getPoliceNo, bo.getPoliceNo());
@ -93,7 +93,7 @@ public class BizSalaryServiceImpl implements IBizSalaryService {
lqw.eq(StringUtils.isNotBlank(bo.getBankCard()), BizSalary::getBankCard, bo.getBankCard());
lqw.eq(StringUtils.isNotBlank(bo.getDeptId()), BizSalary::getDeptId, bo.getDeptId());
lqw.like(StringUtils.isNotBlank(bo.getDeptName()), BizSalary::getDeptName, bo.getDeptName());
lqw.eq(StringUtils.isNotBlank(bo.getYearMonth()), BizSalary::getYearMonth, bo.getYearMonth());
lqw.eq(StringUtils.isNotBlank(bo.getSalaryYearMonth()), BizSalary::getSalaryYearMonth, bo.getSalaryYearMonth());
lqw.eq(bo.getSalaryYear() != null, BizSalary::getSalaryYear, bo.getSalaryYear());
lqw.eq(bo.getSalaryMonth() != null, BizSalary::getSalaryMonth, bo.getSalaryMonth());
lqw.eq(bo.getPostSalary() != null, BizSalary::getPostSalary, bo.getPostSalary());

View File

@ -58,15 +58,22 @@ public class BizSalaryImportListener extends AnalysisEventListener<BizSalaryImpo
@Override
public void invoke(BizSalaryImportVo importVo, AnalysisContext context) {
BizSalaryVo salaryVo = this.salaryService.selectSalaryByIdCardAndMouth(importVo.getIdcard(), importVo.getYearMonth());
BizSalaryVo salaryVo = this.salaryService.selectSalaryByIdCardAndMouth(importVo.getIdcard(), importVo.getSalaryYearMonth());
try {
SysUserVo dbUser = this.userService.selectUserByIdCard(importVo.getIdcard());
if (ObjectUtil.isNull(dbUser)){
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、工资明细导入失败,民警 ")
.append(salaryVo.getPoliceName())
.append(salaryVo.getIdcard())
.append(" 不存在");
}else {
importVo.setUserId(dbUser.getUserId());
importVo.setPoliceNo(dbUser.getUserName());
importVo.setDeptId(dbUser.getWorkDeptId());
importVo.setDeptName(dbUser.getWorkDeptName());
// 验证是否存在这个用户
// 验证是否存在这条 工资明细记录
if (ObjectUtil.isNull(salaryVo)) {
BizSalaryBo salary = BeanUtil.toBean(importVo, BizSalaryBo.class);
@ -90,6 +97,7 @@ public class BizSalaryImportListener extends AnalysisEventListener<BizSalaryImpo
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("、工资明细 ").append(salaryVo.getPoliceName()).append(" 已存在");
}
}
} catch (Exception e) {
failureNum++;
String msg = "<br/>" + failureNum + "、工资明细 " + HtmlUtil.cleanHtmlTag(salaryVo.getPoliceName()) + " 导入失败:";

View File

@ -0,0 +1,17 @@
package com.ruans.system.service;
/**
* <p>description: </p>
* PKI
* @author chenle
* @date 2020/5/6 17:19
*/
public interface PKIAuthService {
/**
* pki
* @return
*/
String pkiAuth(String signData,String originalNum) throws Exception;
String generateOriginalNum();
}

View File

@ -0,0 +1,119 @@
package com.ruans.system.service.impl;
import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* 使HTTPCLIENT
HttpClient
使
socket factory test.MySecureProtocolSocketFactory org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory X509TrustManager(test.MyX509TrustManager)
org.apache.commons.httpclient.protocol.Protocol
Protocol myhttps = new Protocol("https", new MySecureProtocolSocketFactory (), 443);
https
Protocol.registerProtocol("https ", myhttps);
* @author admin
*
*/
public class HTTPSSecureProtocolSocketFactory implements ProtocolSocketFactory {
private SSLContext sslcontext = null;
private SSLContext createSSLContext() {
SSLContext sslcontext = null;
try {
sslcontext = SSLContext.getInstance("SSL");
sslcontext.init(null,
new TrustManager[] { new TrustAnyTrustManager() },
new java.security.SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return sslcontext;
}
private SSLContext getSSLContext() {
if (null == this.sslcontext) {
this.sslcontext = createSSLContext();
}
return this.sslcontext;
}
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(socket, host,
port, autoClose);
}
@Override
public Socket createSocket(String host, int port) throws IOException,
UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress clientHost,
int clientPort) throws IOException, UnknownHostException {
return getSSLContext().getSocketFactory().createSocket(host, port,
clientHost, clientPort);
}
@Override
public Socket createSocket(String host, int port, InetAddress localAddress,
int localPort, HttpConnectionParams params) throws IOException,
UnknownHostException, ConnectTimeoutException {
if (params == null) {
throw new IllegalArgumentException("Parameters may not be null");
}
int timeout = params.getConnectionTimeout();
SocketFactory socketfactory = getSSLContext().getSocketFactory();
if (timeout == 0) {
return socketfactory.createSocket(host, port, localAddress,
localPort);
} else {
Socket socket = socketfactory.createSocket();
SocketAddress localaddr = new InetSocketAddress(localAddress,
localPort);
SocketAddress remoteaddr = new InetSocketAddress(host, port);
socket.bind(localaddr);
socket.connect(remoteaddr, timeout);
return socket;
}
}
private static class TrustAnyTrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
}

View File

@ -0,0 +1,449 @@
package com.ruans.system.service.impl;
import cn.hutool.core.codec.Base64Encoder;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import com.ruans.common.core.utils.AuthResult;
import com.ruans.common.core.utils.PKIUtils;
import com.ruans.system.service.PKIAuthService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* <p>description: </p>
* PKI
* @author chenle
* @date 2020/5/6 17:20
*/
@Service
public class PKIAuthServiceImpl implements PKIAuthService {
@Value("${pki.authUrl}")
private String authUrl;
// @Value("${pki.appId}")
private String appId = "08028340800";
@Value("${pki.remoteAddr}")
private String remoteAddr;
/**
* pki
* @param signData html signData
* @return
*/
@Override
public String pkiAuth(String signData,String originalNum) throws Exception {
//产生原文
// String originalNum = PKIUtils.generateOriginalNum();
// String original_data_base64 = Base64Utils.encodeToString(originalNum.getBytes());
String original_data_base64 = Base64Encoder.encode(originalNum.getBytes());
AuthResult result = reqToData(original_data_base64, signData);
Map certAttributeNodeMap = result.getCertAttributeNodeMap();
Iterator iterator = certAttributeNodeMap.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry entry = (Map.Entry)(iterator.next());
System.out.println("值为="+entry.getValue());
return entry.getValue().toString();
}
return null;
}
@Override
public String generateOriginalNum() {
return PKIUtils.generateOriginalNum();
}
/**
*
* @param original_data_base64 base64
* @param signed_data
* @return
*/
public AuthResult reqToData(String original_data_base64, String signed_data) throws IOException, DocumentException {
byte[] messagexml = null;
boolean isSuccess = true;
String errCode = null;
String errDesc = null;
AuthResult authResult = new AuthResult();
Document reqDocument = DocumentHelper.createDocument();
Element root = reqDocument.addElement(PKIUtils.CommonConstant.MSG_ROOT);
Element requestHeadElement = root.addElement(PKIUtils.CommonConstant.MSG_HEAD);
Element requestBodyElement = root.addElement(PKIUtils.CommonConstant.MSG_BODY);
// 组装报文头信息 ,组装认证xml文件时进行判断如果配置调用应用服务器生成原文则生成xml version版本为1.0
requestHeadElement.addElement(PKIUtils.CommonConstant.MSG_VSERSION).setText(
PKIUtils.CommonConstant.MSG_VSERSION_VALUE_10);
// 服务类型 AuthenService
requestHeadElement.addElement(PKIUtils.CommonConstant.MSG_SERVICE_TYPE).setText(
PKIUtils.AuthConstant.MSG_SERVICE_TYPE_VALUE);
// 组装报文体信息
// 组装客户端信息
Element clientInfoElement = requestBodyElement.addElement(PKIUtils.AuthConstant.MSG_CLIENT_INFO);
Element clientIPElement = clientInfoElement.addElement(PKIUtils.AuthConstant.MSG_CLIENT_IP);
clientIPElement.setText(remoteAddr);
// 组装应用标识信息
requestBodyElement.addElement(PKIUtils.CommonConstant.MSG_APPID).setText(appId);
Element authenElement = requestBodyElement.addElement(PKIUtils.AuthConstant.MSG_AUTH);
Element authCredentialElement = authenElement.addElement(PKIUtils.AuthConstant.MSG_AUTHCREDENTIAL);
// detach认证请求包Detach格式的认证请求包中不包含认证原文
// 所以需要与<original>节点配合使用将认证原文提交给网关。
// original网关颁发的认证原文原文在提交认证时需经过Base64编码
authCredentialElement.addAttribute(PKIUtils.AuthConstant.MSG_AUTH_MODE,
PKIUtils.AuthConstant.MSG_AUTH_MODE_CERT_VALUE);
authCredentialElement.addElement(PKIUtils.AuthConstant.MSG_DETACH).setText(
signed_data);
authCredentialElement.addElement(PKIUtils.CommonConstant.MSG_ORIGINAL).setText(
original_data_base64);
// 是否检查访问控制状态
requestBodyElement.addElement(PKIUtils.AuthConstant.MSG_ACCESS_CONTROL).
//setText(configMap.get(ConfigConstant.KEY_ACCESS_CONTROL));
setText("false");
// 组装属性查询列表信息
Element attributesElement = requestBodyElement.addElement(PKIUtils.AuthConstant.MSG_ATTRIBUTES);
attributesElement.addAttribute(PKIUtils.AuthConstant.MSG_ATTRIBUTE_TYPE, PKIUtils.AuthConstant.MSG_ATTRIBUTE_TYPE_ALL);
StringBuilder reqMessageData = new StringBuilder();
try {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
XMLWriter writer = new XMLWriter(outStream);
writer.write(reqDocument);
messagexml = outStream.toByteArray();
reqMessageData.append("请求内容开始!\n");
reqMessageData.append(outStream.toString() + "\n");
reqMessageData.append("请求内容结束!\n");
System.out.println(reqMessageData.toString() + "\n");
} catch (Exception e) {
isSuccess = false;
errDesc = "组装认证请求报文出现异常";
System.out.println("组装认证请求报文出现异常" + e.getMessage());
}
System.out.println("组装认证请求报文结束");
// 创建与网关的HTTP连接发送认证请求报文并接收认证响应报文
// 创建与网关的HTTP连接 开始
int statusCode = 500;
HttpClient httpClient = null;
PostMethod postMethod = null;
//PostMethod postMethod = null;
if (isSuccess) {
System.out.println("向网关发送认证请求开始");
System.out.println("向网关发送认证请求开始");
// HTTPClient对象
System.out.print(authUrl);
httpClient = new HttpClient();
postMethod = new PostMethod(authUrl);
postMethod.setRequestHeader("Connection", "close");
// 设置报文传送的编码格式
postMethod.setRequestHeader("Content-Type", "text/xml;charset=UTF-8");
// 设置发送认证请求内容开始
postMethod.setRequestBody(new ByteArrayInputStream(messagexml));
// 设置发送认证请求内容结束
// 执行postMethod
try {
URL url = protocol(authUrl);
// 发送通讯报文与网关通讯
statusCode = httpClient.executeMethod(postMethod);
if (url != null && "https".equals(url.getProtocol())) {
Protocol.unregisterProtocol("https");
}
} catch (Exception e) {
isSuccess = false;
errCode = String.valueOf(statusCode);
errDesc = e.getMessage();
System.out.println("向网关发送认证请求失败:与网关连接出现异常:" + errDesc);
postMethod.releaseConnection();
httpClient.getHttpConnectionManager().closeIdleConnections(0);
httpClient = null;
throw e;
}
System.out.println("向网关发送认证请求结束");
}
// 读取网关返回的认证响应报文
StringBuffer respMessageData = new StringBuffer();
String respMessageXml = null;
if (isSuccess) {
System.out.println("读取网关返回的认证响应报文开始");
// 当返回200或500状态时处理业务逻辑
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
// 从头中取出转向的地址
try {
// 接收通讯报文并处理开始
byte[] inputstr = postMethod.getResponseBody();
ByteArrayInputStream ByteinputStream = new ByteArrayInputStream(inputstr);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int ch = 0;
try {
while ((ch = ByteinputStream.read()) != -1) {
int upperCh = (char) ch;
outStream.write(upperCh);
}
} catch (Exception e) {
isSuccess = false;
errDesc = e.getMessage();
}
if (isSuccess) {
// 200 表示返回处理成功
if (statusCode == HttpStatus.SC_OK) {
respMessageData.append("响应内容开始!\n");
respMessageData.append(new String(outStream.toByteArray(), "UTF-8") + "\n");
respMessageData.append("响应内容结束!\n");
respMessageXml = new String(outStream.toByteArray(), "UTF-8");
} else {
// 500 表示返回失败,发生异常
respMessageData.append("响应500内容开始\n");
respMessageData.append(new String(outStream.toByteArray()) + "\n");
respMessageData.append("响应500内容结束\n");
isSuccess = false;
errCode = String.valueOf(statusCode);
errDesc = new String(outStream.toByteArray());
}
System.out.println(respMessageData.toString());
}
// 接收通讯报文并处理结束
} catch (IOException e) {
isSuccess = false;
errCode = String.valueOf(statusCode);
errDesc = e.getMessage();
System.out.println("读取网关返回的认证响应报文出现异常:" + errDesc);
} finally {
if (httpClient != null) {
postMethod.releaseConnection();
httpClient.getHttpConnectionManager().closeIdleConnections(0);
}
}
}
System.out.println("读取网关返回的认证响应报文结束");
}
// 服务端处理(解析网关返回的认证响应报文)
Document respDocument = null;
Element headElement = null;
Element bodyElement = null;
if (isSuccess) {
System.out.println("解析网关返回的认证响应报文开始");
// 特殊字符'&'处理
respMessageXml = respMessageXml.replaceAll("&", "&amp;");
respDocument = DocumentHelper.parseText(respMessageXml);
headElement = respDocument.getRootElement().element(PKIUtils.CommonConstant.MSG_HEAD);
bodyElement = respDocument.getRootElement().element(PKIUtils.CommonConstant.MSG_BODY);
// 解析报文头
if (headElement != null) {
boolean state = Boolean.valueOf(
headElement.elementTextTrim(PKIUtils.CommonConstant.MSG_MESSAGE_STATE));
if (state) {
isSuccess = false;
errCode = headElement.elementTextTrim(PKIUtils.CommonConstant.MSG_MESSAGE_CODE);
errDesc = headElement.elementTextTrim(PKIUtils.CommonConstant.MSG_MESSAGE_DESC);
System.out.println("网关认证业务处理失败!\t" + errDesc + "\n");
}
}
}
if (isSuccess) {
System.out.println("解析报文头成功!\n");
// 解析报文体
// 解析认证结果集
Element authResultElement = bodyElement.element(PKIUtils.AuthConstant.MSG_AUTH_RESULT_SET)
.element(PKIUtils.AuthConstant.MSG_AUTH_RESULT);
isSuccess = Boolean.valueOf(authResultElement.attributeValue(PKIUtils.AuthConstant.MSG_SUCCESS));
if (!isSuccess) {
errCode = authResultElement.elementTextTrim(PKIUtils.AuthConstant.MSG_AUTH_MESSSAGE_CODE);
errDesc = authResultElement.elementTextTrim(PKIUtils.AuthConstant.MSG_AUTH_MESSSAGE_DESC);
System.out.println("身份认证失败,失败原因:" + errDesc);
}
}
if (isSuccess) {
System.out.println("身份认证成功!\n");
String accessControlResult = bodyElement.elementTextTrim("accessControlResult");
System.out.println("网关根据规则对该用户计算的访问控制结果:" + accessControlResult);
// 设置返回认证结果信息
authResult.setAccessControlResult(accessControlResult);
if ("Deny".equals(accessControlResult)) {
isSuccess = false;
errCode = "-1";
errDesc = "该用户无权限访问此应用";
} else {
// 解析用户属性列表
Element attrsElement = bodyElement.element(PKIUtils.AuthConstant.MSG_ATTRIBUTES);
if (attrsElement != null) {
//List<Element> namespacesElements = (List<Element>)attrsElement
List namespacesElements = (List) attrsElement
.elements(PKIUtils.AuthConstant.MSG_ATTRIBUTE);
if (namespacesElements != null
&& namespacesElements.size() > 0) {
System.out.println("属性个数:" + namespacesElements.size());
for (int i = 0; i < namespacesElements.size(); i++) {
//String arrs = namespacesElements.get(i).attributeValue(AuthConstant.MSG_NAMESPACE);
String arrs = ((Element) namespacesElements.get(i)).attributeValue(PKIUtils.AuthConstant.MSG_NAMESPACE);
System.out.println(arrs);
}
/*Map<String[],String> certAttributeNodeMap = new HashMap<String[],String>();
Map<String[],String> childAttributeNodeMap = new HashMap<String[],String>();
Map<String[],String> umsAttributeNodeMap = new HashMap<String[],String>();
Map<String[],String> pmsAttributeNodeMap = new HashMap<String[],String>();*/
Map certAttributeNodeMap = new HashMap();
Map childAttributeNodeMap = new HashMap();
Map umsAttributeNodeMap = new HashMap();
Map pmsAttributeNodeMap = new HashMap();
Map customAttributeNodeMap = new HashMap();
String[] keyes = new String[2];
if (attrsElement != null) {
List attributeNodeList = attrsElement
.elements(PKIUtils.AuthConstant.MSG_ATTRIBUTE);
for (int i = 0; i < attributeNodeList.size(); i++) {
keyes = new String[2];
Element userAttrNode = (Element) attributeNodeList.get(i);
String msgParentName = userAttrNode
.attributeValue(PKIUtils.AuthConstant.MSG_PARENT_NAME);
String name = userAttrNode
.attributeValue(PKIUtils.AuthConstant.MSG_NAME);
String value = userAttrNode.getTextTrim();
keyes[0] = name;
childAttributeNodeMap.clear();
//String arrs = namespacesElements.get(i).attributeValue(AuthConstant.MSG_NAMESPACE);
String arrs = ((Element) namespacesElements.get(i)).attributeValue(PKIUtils.AuthConstant.MSG_NAMESPACE);
if (arrs.trim().equals(PKIUtils.AuthConstant.KEY_NAMESPACE_CINAS)) {
// 证书信息
if (msgParentName != null
&& !msgParentName.equals("")) {
keyes[1] = msgParentName;
if (value != null && value.length() > 0)
childAttributeNodeMap.put(keyes, value);
} else {
if (value != null && value.length() > 0)
certAttributeNodeMap.put(keyes, value);
}
certAttributeNodeMap.putAll(childAttributeNodeMap);
} else if (arrs.trim().equals(PKIUtils.AuthConstant.KEY_NAMESPACE_UMS)) {
// UMS信息
if (msgParentName != null
&& !msgParentName.equals("")) {
keyes[1] = msgParentName;
if (value != null && value.length() > 0)
childAttributeNodeMap.put(keyes, value);
} else {
if (value != null && value.length() > 0)
umsAttributeNodeMap.put(keyes, value);
}
umsAttributeNodeMap.putAll(childAttributeNodeMap);
//} else if (arrs.trim().contains(AuthConstant.KEY_NAMESPACE_PMS)) {
} else if (arrs.trim().indexOf(PKIUtils.AuthConstant.KEY_NAMESPACE_PMS) != -1) {
// PMS信息
if (msgParentName != null
&& !msgParentName.equals("")) {
keyes[1] = msgParentName;
if (value != null && value.length() > 0)
childAttributeNodeMap.put(keyes, value);
} else {
if (value != null && value.length() > 0)
pmsAttributeNodeMap.put(keyes, value);
}
pmsAttributeNodeMap.putAll(childAttributeNodeMap);
} else if (arrs.trim().indexOf(PKIUtils.AuthConstant.KEY_NAMESPACE_CUSTOM) != -1) {
// 自定义信息
if (msgParentName != null
&& !msgParentName.equals("")) {
keyes[1] = msgParentName;
if (value != null && value.length() > 0)
childAttributeNodeMap.put(keyes, value);
} else {
if (value != null && value.length() > 0)
customAttributeNodeMap.put(keyes, value);
}
customAttributeNodeMap.putAll(childAttributeNodeMap);
} else {
// 如果有其他的属性信息添加到证书信息里面
if (msgParentName != null && !msgParentName.equals("")) {
keyes[1] = msgParentName;
if (value != null && value.length() > 0)
childAttributeNodeMap.put(keyes, value);
} else {
if (value != null && value.length() > 0)
certAttributeNodeMap.put(keyes, value);
}
certAttributeNodeMap.putAll(childAttributeNodeMap);
}
}
// 设置返回认证结果信息
authResult.setCertAttributeNodeMap(certAttributeNodeMap);
authResult.setUmsAttributeNodeMap(umsAttributeNodeMap);
authResult.setPmsAttributeNodeMap(pmsAttributeNodeMap);
authResult.setCustomAttributeNodeMap(customAttributeNodeMap);
}
}
}
}
}
return authResult;
}
/**
*
* @param authURL
* @return
*/
public static URL protocol(String authURL){
// 发送原文请求报文与网关通讯
URL url = getUrl(authURL);
if(url != null && "https".equals(url.getProtocol())){
int port = 443;
if(url.getPort() != -1){
port = url.getPort();
}
Protocol https = new Protocol("https", new HTTPSSecureProtocolSocketFactory(), port);
Protocol.registerProtocol("https", https);
}
return url;
}
/**
* url
* @param urlAddress
* @return
*/
private static URL getUrl(String urlAddress){
URL url = null;
try {
url = new URL(urlAddress);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}
}