package com.infosec.ztpdp.policycenter.component.log;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>
* 自定义日志注解
* </p>
*
* <p>
* 版权所有:北京信安世纪科技股份有限公司
* </p>
*
* @author lbw
* @date 2022年6月30日
*
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
/**
* <p>Title: logtype</p>
* <p>Description: 日志类型 默认为"" 即为管理员操作日志,注册日志="registeruser"</p>
* @return
* @author lbw
* @date 2022年7月8日
*/
String logtype() default "";
/**
* <p>Title: paramKey</p>
* <p>Description: 记录日志信息 需要从参数中取值当做日志参数时 设置此参数为所需参数key</p>
* @return
* @author lbw
* @date 2022年7月8日
*/
String paramKey() default "";
}
package com.infosec.ztpdp.policycenter.component.log;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSONObject;
import com.infosec.ztpdp.policycenter.common.jsonresult.JsonErrotCode;
import com.infosec.ztpdp.policycenter.common.jsonresult.JsonResult;
import com.infosec.ztpdp.policycenter.common.login.LoginUserUtil;
import com.infosec.ztpdp.policycenter.common.login.UserLoginBean;
import com.infosec.ztpdp.policycenter.common.util.Const;
import com.infosec.ztpdp.policycenter.common.util.GetMacAddress;
import com.infosec.ztpdp.policycenter.common.util.UebaInternationKeyConst;
import com.infosec.ztpdp.policycenter.common.util.log.Log;
import com.infosec.ztpdp.policycenter.common.util.log.LogConst;
import com.infosec.ztpdp.policycenter.component.LocaleMessageSourceService;
import io.swagger.annotations.ApiOperation;
/**
* <p>
* 切面记录日志
* </p>
*
* <p>
* 版权所有:北京信安世纪科技股份有限公司
* </p>
*
* @author lbw
* @date 2022年6月28日
*
*/
@Aspect
@Configuration
public class LogAspect {
private final String EXTERNAL_INTERFACE = "/api/" ;
private final String OPEN_API = "/openapi/" ;
private final String CLIENT_NO_FILTER = "/client/" ;
private final String VERIFICATIONCODE_NO_FILTER = "/v1/verificationCode" ;
@Resource
private LocaleMessageSourceService localeMessageSourceService;
@Autowired
private Log log;
public LogAspect() {
}
@Pointcut("@within(com.infosec.ztpdp.policycenter.component.log.LogAnnotation) || @annotation(com.infosec.ztpdp.policycenter.component.log.LogAnnotation)")
public void pointCutMethod() {
}
/**
* 声明环绕通知
*/
@Around("pointCutMethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Long startTime = System.currentTimeMillis();
// 获取request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
Object ret = null;
if(sra == null) {
ret = pjp.proceed();
return ret;
}
HttpServletRequest request = sra.getRequest();
String requestUri = request.getServletPath();
UserLoginBean localUser = LoginUserUtil.getLoginUserBean(request);
boolean exceptionFlag = false;
String requestParam = null ;
if(requestUri.startsWith(EXTERNAL_INTERFACE) || requestUri.startsWith(OPEN_API)) {
requestParam = getParam(pjp).toString() ;
}
try {
ret = pjp.proceed();
} catch (Exception e) {
// TODO: handle exception
if(requestUri != null && requestUri.indexOf(Const.EXPORT_1) != -1) {
exceptionFlag = true;
}else {
throw e;
}
}
Long endTime = System.currentTimeMillis();
//设置请求路径
if(StringUtils.isEmpty(requestUri) || requestUri.contains(CLIENT_NO_FILTER) || requestUri.contains(VERIFICATIONCODE_NO_FILTER)) {
//
}else {
addLog(request,requestUri,exceptionFlag,localUser,pjp,endTime-startTime,ret,requestParam);
}
return ret;
}
/**
* 获取参数名和参数值
*/
public JSONObject getParam(ProceedingJoinPoint proceedingJoinPoint) {
JSONObject paramObj = new JSONObject() ;
Object[] values = proceedingJoinPoint.getArgs();
String[] names = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
for (int i = 0; i < names.length; i++) {
String key = names[i] ;
// 剔除httprequest
if("request".equals(key) || "response".equals(key)){
continue ;
}
paramObj.put(key, values[i]);
}
return paramObj;
}
private void addLog(HttpServletRequest request,String requestUri,boolean exceptionFlag,UserLoginBean localUser
,ProceedingJoinPoint pjp,Long time,Object ret,String requestParam) throws IOException {
String apiName;
String logType;
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
apiName = Objects.nonNull(apiOperation) ? apiOperation.value() : "";
LogAnnotation annotation = method.getAnnotation(LogAnnotation.class);
if(annotation == null) {
annotation = pjp.getTarget().getClass().getAnnotation(LogAnnotation.class);
}
logType = annotation.logtype();
String msg = "";
String code = "";
String model = "";
String appName = "";
String operation = "";
int logLevel = Log.LOG_LEVEL_WARN;
int result = Log.RESULT_FAIULE;
String[] split = requestUri.split("/");
appName = !StringUtils.isEmpty(split[1])? split[1] : appName;
model = !StringUtils.isEmpty(split[2])? split[2] : model;
operation = !StringUtils.isEmpty(split[3])? split[3] : operation;
// 存放扩展参数
JSONObject extendParam = new JSONObject() ;
JsonResult res = null;
if(ret!= null && ret instanceof JsonResult) {
res = (JsonResult) ret ;
code = res.getCode();
msg = res.getMsg();
extendParam.put("requestUrl", requestUri) ;
extendParam.put("requestParam", requestParam) ;
extendParam.put("requestResult", res.toJsonString()) ;
}else if(ret!= null && ret instanceof JSONObject){
JSONObject resJson = (JSONObject) ret ;
code = resJson.getString("code");
msg = resJson.getString("msg");
extendParam.put("requestUrl", requestUri) ;
extendParam.put("requestParam", requestParam) ;
extendParam.put("requestResult", resJson.toJSONString()) ;
}else if(ret!= null && ret instanceof String){
JSONObject resJson = JSONObject.parseObject((String)ret) ;
code = resJson.getString("resultcode");
code = "000000".equals(code) ? JsonErrotCode.SUCCESS_CODE:JsonErrotCode.PARAM_ERROR ;
msg = resJson.getString("resultmsg");
extendParam.put("requestUrl", requestUri) ;
extendParam.put("requestParam", requestParam) ;
extendParam.put("requestResult", resJson.toJSONString()) ;
}else {
if(requestUri.contains(Const.GETQRCODE)) {
extendParam.put("requestUrl", requestUri) ;
extendParam.put("requestParam", requestParam) ;
}
}
//没有响应 且操作类型为导出
if(ret == null && Const.EXPORT.equals(operation)) {
//根据是否异常来设置code和msg
if(exceptionFlag) {
code = JsonErrotCode.FAIL_CODE;
}else {
code = JsonErrotCode.SUCCESS_CODE;
}
}
String localUserLoginName = "";
String localUserName = "";
String localUserRoles = "";
String userClientIp = "";
if(Const.GET.equals(operation)) {
operation = Log.HOWS_READ;
}else if (Const.POST.equals(operation)) {
operation = Log.HOWS_MODIFY;
}else if (Const.DEL.equals(operation)) {
operation = Log.HOWS_DEL;
}else if (Const.ADD.equals(operation)) {
operation = Log.HOWS_ADD;
}else if (Const.LOGIN.equals(operation)) {
operation = Log.HOWS_LOGIN;
}else if (Const.SINGLEPOINT.equals(operation)) {
operation = Log.HOWS_LOGOUT;
}else if (Const.EXPORT.equals(operation)) {
operation = Log.HOWS_EXPORT;
}else if (Const.IMPORT.equals(operation)) {
operation = Log.HOWS_IMPORT;
}else if (Const.DOWNLOAD.equals(operation)) {
operation = Log.HOWS_DOWNLOAD;
}else {
operation = Log.HOWS_OTHERS;
}
if(LogConst.MODEL_FLAG_PORTAL.equals(logType) ) {
model = LogConst.MODEL_UEBA;
}
//没有登录调用接口(对外API,注册)
if (localUser == null) {
//对外API
if( LogConst.LOGTYPE_API.equals(appName) ) {
String header = request.getHeader(Const.APPID);
localUserLoginName = header;
localUserName = header;
appName = header;
model = LogConst.LOGTYPE_API;
userClientIp = GetMacAddress.getIpAddr(request);
}else if(LogConst.OPEN_API.equals(appName)) {
localUserLoginName = LogConst.ZEROTRUST_CLIENT;
localUserName = LogConst.ZEROTRUST_CLIENT;
appName = LogConst.ZEROTRUST_CLIENT;
model = LogConst.LOGTYPE_API;
if(requestParam != null) {
JSONObject reqestObj = JSONObject.parseObject(requestParam) ;
if(requestUri.contains(Const.DYNAMICPDP_FORNETGATE) || requestUri.contains(Const.DEVICEENVCHANGED) ) {
userClientIp = reqestObj.getJSONObject("param").getJSONObject("dattrs").getString("internetIp") ;
}
if(StringUtils.isEmpty(userClientIp)) {
userClientIp = reqestObj.getString("intranetIp") ;
}
if(StringUtils.isEmpty(userClientIp)) {
JSONObject paramJson1 = reqestObj.getJSONObject("param") ;
if(paramJson1!=null) {
userClientIp = paramJson1.getString("intranetIp") ;
if(StringUtils.isEmpty(userClientIp)) {
userClientIp = paramJson1.getString("internetIp") ;
}
}
}
extendParam.put("deviceId", reqestObj.getString("deviceId")) ;
}
}else if(LogConst.MODEL_FLAG_PORTAL.equals(logType) ) {
if(requestUri.indexOf(Const.GET_1) != -1) {
operation = Log.HOWS_READ;
}else if (requestUri.indexOf(Const.UPDATE) != -1) {
operation = Log.HOWS_MODIFY;
}else if (requestUri.indexOf(Const.ADD_1) != -1) {
operation = Log.HOWS_ADD;
}
localUserRoles = "commonuser";
//普通用户调用日志 没有登录时取参数内的登录名做日志参数
String paramKey = annotation.paramKey();
Map<String, Object> param = getParam(pjp);
localUserLoginName = (String) param.get(paramKey);
localUserName = localUserLoginName;
}
userClientIp = GetMacAddress.getIpAddr(request);
}else {
localUserLoginName = localUser.getLoginName();
localUserName = localUser.getUsername();
localUserRoles = localUser.getSystemrole();
userClientIp = localUser.getClientip();
}
// 设置请求状态
if(JsonErrotCode.SUCCESS_CODE.equals(code)) {
logLevel = Log.LOG_LEVEL_INFO;
result = Log.RESULT_SUCCESS;
if(StringUtils.isEmpty(msg)) {
msg = apiName + "成功";
}
} else if(JsonErrotCode.PARAM_ERROR.equals(code)) {
logLevel = Log.LOG_LEVEL_WARN;
result = Log.RESULT_FAIULE;
if(StringUtils.isEmpty(msg)) {
msg = apiName + "失败";
}
} else if(JsonErrotCode.FAIL_CODE.equals(code)) {
logLevel = Log.LOG_LEVEL_ERROR;
result = Log.RESULT_FAIULE;
msg = apiName+" 异常 " + (StringUtils.isEmpty(msg) ? "" : msg);
if(res != null) {
res.setMsg(localeMessageSourceService.getMessage(UebaInternationKeyConst.SYS_EXCEPTION));
}
if(!LogConst.LOGTYPE_API.equals(LogConst.LOGTYPE_API)) {
model = LogConst.MODEL_UEBA;
}
}
log.writeLog(this.getClass().getName(), logLevel, model, localUserLoginName, userClientIp,
operation, result, msg, localUserName, localUserRoles,
appName,requestUri,extendParam);
}
}
package com.infosec.ztpdp.policycenter.component.login;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.infosec.ztpdp.policycenter.common.jsonresult.JsonErrotCode;
import com.infosec.ztpdp.policycenter.common.jsonresult.JsonResult;
import com.infosec.ztpdp.policycenter.common.login.LoginUserUtil;
import com.infosec.ztpdp.policycenter.common.login.UserLoginBean;
import com.infosec.ztpdp.policycenter.common.redisbase.Db0CacheUtils;
import com.infosec.ztpdp.policycenter.common.util.Const;
import com.infosec.ztpdp.policycenter.common.util.CookieUtil;
import com.infosec.ztpdp.policycenter.common.util.SsoInternationKeyConst;
import com.infosec.ztpdp.policycenter.common.util.log.Log;
import com.infosec.ztpdp.policycenter.common.util.log.LogConst;
import com.infosec.ztpdp.policycenter.component.LocaleMessageSourceService;
import io.swagger.annotations.ApiOperation;
/**
* <p>
* 切面记录日志
* </p>
*
* <p>
* 版权所有:北京信安世纪科技股份有限公司
* </p>
*
* @author lbw
* @date 2022年6月28日
*
*/
@Aspect
@Configuration
public class LoginOutLogAspect {
@Autowired
private Db0CacheUtils db0CacheUtils;
@Resource
private LocaleMessageSourceService localeMessageSourceService;
@Autowired
private Log log;
public LoginOutLogAspect() {
}
@Pointcut("@within(com.infosec.ztpdp.policycenter.component.login.LoginOutLogAnnotation) || @annotation(com.infosec.ztpdp.policycenter.component.login.LoginOutLogAnnotation)")
public void pointCutMethod() {
}
// 声明环绕通知
@Around("pointCutMethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
Long startTime = System.currentTimeMillis();
// 获取request对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
Object ret = null;
if(sra == null) {
ret = pjp.proceed();
return ret;
}
HttpServletRequest request = sra.getRequest();
UserLoginBean localUser = LoginUserUtil.getLoginUserBean(request);
String requestURI = request.getServletPath();
String logType;
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
LoginOutLogAnnotation annotation = method.getAnnotation(LoginOutLogAnnotation.class);
if(annotation == null) {
annotation = pjp.getTarget().getClass().getAnnotation(LoginOutLogAnnotation.class);
}
logType = annotation.logtype();
if(LogConst.LOGTYPE_USER_LOGOUT.equals(logType) || LogConst.LOGTYPE_ADMIN_LOGOUT.equals(logType)) {
String token = CookieUtil.getCookieValue(request, Const.TGCM_ID);
if (!StringUtils.isEmpty(token)) {
String userinfo = db0CacheUtils.get(token);
if(!StringUtils.isEmpty(userinfo)) {
// json对象转字符串
JSONObject jsonObject = JSONObject.parseObject(userinfo);
localUser = JSONObject.parseObject(JSON.toJSONString(jsonObject.get("idInfo")),UserLoginBean.class);
}
}
}
boolean exceptionFlag = false;
String requestParam = null ;
if(requestURI.startsWith(Const.EXTERNAL_INTERFACE)) {
requestParam = getParam(pjp).toString() ;
}
try {
ret = pjp.proceed();
} catch (Exception e) {
if(requestURI != null && requestURI.indexOf("/export/") != -1) {
exceptionFlag = true;
}else {
throw e;
}
}
Long endTime = System.currentTimeMillis();
//设置请求路径
if(StringUtils.isEmpty(requestURI) || requestURI.contains(Const.CLIENT_NO_FILTER)) {
//
}else {
addLog(request,requestURI,exceptionFlag,localUser,pjp,endTime-startTime,ret,requestParam);
}
return ret;
}
//获取参数名和参数值
public JSONObject getParam(ProceedingJoinPoint proceedingJoinPoint) {
JSONObject paramObj = new JSONObject() ;
Object[] values = proceedingJoinPoint.getArgs();
String[] names = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
for (int i = 0; i < names.length; i++) {
paramObj.put(names[i], values[i]);
}
return paramObj;
}
private void addLog(HttpServletRequest request,String requestURI,boolean exceptionFlag,UserLoginBean localUser
,ProceedingJoinPoint pjp,Long time,Object ret,String requestParam) throws IOException {
String apiName;
String logType;
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
apiName = Objects.nonNull(apiOperation) ? apiOperation.value() : "";
LoginOutLogAnnotation annotation = method.getAnnotation(LoginOutLogAnnotation.class);
if(annotation == null) {
annotation = pjp.getTarget().getClass().getAnnotation(LoginOutLogAnnotation.class);
}
logType = annotation.logtype();
String msg = "";
String code = "";
String model = "";
String appName = "";
String operation = "";
int logLevel = Log.LOG_LEVEL_WARN;
int result = Log.RESULT_FAIULE;
String[] split = requestURI.split("/");
appName = !StringUtils.isEmpty(split[1])? split[1] : appName;
model = !StringUtils.isEmpty(split[2])? split[2] : model;
operation = !StringUtils.isEmpty(split[3])? split[3] : operation;
// 存放扩展参数
JSONObject extendParam = new JSONObject() ;
JsonResult res = null;
if(ret!= null && ret instanceof JsonResult) {
res = (JsonResult) ret ;
code = res.getCode();
msg = res.getMsg();
extendParam.put("requestUrl", requestURI) ;
extendParam.put("requestParam", requestParam) ;
extendParam.put("requestResult", res.toJsonString()) ;
}
//没有响应 且操作类型为导出
if(ret == null && ("export".equals(operation) || LogConst.LOGTYPE_USER_LOGOUT.equals(logType) || LogConst.LOGTYPE_ADMIN_LOGOUT.equals(logType))) {
//根据是否异常来设置code和msg
if(exceptionFlag) {
code = JsonErrotCode.FAIL_CODE;
}else {
code = JsonErrotCode.SUCCESS_CODE;
}
}
String localUserLoginName = "";
String localUserName = "";
String localUserRoles = "";
String userClientIp = "";
//根据响应code首字母判断成功失败
if(code.startsWith("I")) {
logLevel = Log.LOG_LEVEL_INFO;
result = Log.RESULT_SUCCESS;
if(StringUtils.isEmpty(msg)) {
msg = apiName + "成功";
}
} else if(code.startsWith("W")) {
logLevel = Log.LOG_LEVEL_WARN;
result = Log.RESULT_FAIULE;
if(StringUtils.isEmpty(msg)) {
msg = apiName + "失败";
}
} else if(code.startsWith("E")) {
logLevel = Log.LOG_LEVEL_ERROR;
result = Log.RESULT_FAIULE;
msg = apiName+" 异常 " + (StringUtils.isEmpty(msg) ? "" : msg);
if(res != null) {
res.setMsg(localeMessageSourceService.getMessage(SsoInternationKeyConst.SYS_EXCEPTION));
}
}
switch (operation) {
case "get":
operation = Log.HOWS_READ; break;
case "update":
operation = Log.HOWS_MODIFY; break;
case "del":
operation = Log.HOWS_DEL; break;
case "add":
operation = Log.HOWS_ADD; break;
case "login":
operation = Log.HOWS_LOGIN; break;
case "export":
operation = Log.HOWS_EXPORT; break;
case "import":
operation = Log.HOWS_IMPORT; break;
case "download":
operation = Log.HOWS_DOWNLOAD; break;
default:
operation = Log.HOWS_OTHERS; break;
}
localUserLoginName = localUser.getLoginName();
localUserName = localUser.getUsername();
localUserRoles = localUser.getSystemrole();
userClientIp = localUser.getClientip();
if(LogConst.LOGTYPE_ADMIN_LOGOUT.equals(logType)) {
appName = LogConst.MODEL_FLAG_PORTAL;
model = LogConst.LOGTYPE_LOGOUT;
operation = Log.HOWS_LOGOUT;
if(LogConst.LOGTYPE_ADMIN_LOGOUT.equals(logType)) {
appName = LogConst.MODEL_FLAG_MANAGER;
if (localUserRoles.equals(Const.ROLE_SUPERADMIN)) {
msg = "超级管理员登出系统";
} else if (localUserRoles.equals(Const.ROLE_SYSADMIN) || localUserRoles.equals(Const.ROLE_SECADMIN)
|| localUserRoles.equals(Const.ROLE_AUDITADMIN)) {
msg = "三员管理员登出系统";
} else {
msg = "组织机构管理员登出系统";
}
if(logLevel == Log.LOG_LEVEL_INFO) {
msg += "成功";
} else if (logLevel == Log.LOG_LEVEL_WARN) {
msg += "失败";
}else if (logLevel == Log.LOG_LEVEL_ERROR) {
msg += "异常";
}
}
}
log.writeLog(this.getClass().getName(), logLevel, model, localUserLoginName, userClientIp,
operation, result, msg, localUserName, localUserRoles,
appName,requestURI,extendParam);
}
}
public void writeLog(String orgClassName, int loglevel, String logcode, String uid, String clientip, String hows,
int result, String describe, String username, String role, String appName, String url,
JSONObject extendParam) {
JSONObject logJsonObject = CommonUtil.buildAopLogObject(orgClassName, loglevel, logcode, uid, clientip, hows,
result, describe, username, role, serviceIp, appName, url, extendParam);
String logModel = "";
boolean isAdmin = StringUtils.isEmpty(role) ? false : judgeAdmin(role);
if (StringUtils.isEmpty(url)) {
// 截取日志编码中代表操作模块的编号。
logModel = logcode.substring(1, 3);
} else {
logModel = logcode;
logcode = url;
logJsonObject.put(LogConst.LOG_LOGCODE, logcode);
logJsonObject.put(LogConst.LOG_LOGMODEL, logModel);
}
switch (logModel) {
case LogConst.LOGTYPE_API:
// 接口访问日志记录
break;
case LogConst.LOGTYPE_LOGOUT:
// 管理员登出日志记录
SynThreadPool.addAuthorityChangeSynRunnable(
new ManagerLogAccessSynRunnable(iManagerAccessLogService, logJsonObject));
break;
default:
if (isAdmin) {
}
}
}