1。引言任何软件系统都不可避免地会遇到【信息安全】这个词,尤其是对于刚入行的新人,比如我。刚入行的时候,领导让我做一个数据报表导出功能,我就照他说的去做。至于谁有权限操作导出,导出的包含敏感信息的数据如何处理,后台接口是否有权限控制防止恶意抢夺,我基本不关心这些问题。只想一心一意尽快实现需求,然后顺利完成任务交付。事实上,随着工作经验的增加,你会越来越觉得,实现业务方的需求只是在软件系统开发中完成“可用”的需求;服务是否“可靠”可能需要从架构层来判断。至于是不是【安全】,我们需要更多的从【信息安全】的角度思考,尤其是当我们的软件系统面临外界的恶意干扰和攻击的时候,它还能保护用户吗?正常使用,对于大公司来说,这可能是重中之重,因为一个小漏洞,一个不小心,可能会给公司造成上千万的损失!最常见的是电商系统和支付系统,尤其是在需求旺季,经常会有黑客专门攻击这些电商系统,导致大量服务宕机,影响用户正常下单。这样的攻击每天都在发生,有的公司甚至直接向黑客发火,出钱消灾!但这种做法绝对不是长久之计,最重要的是要积极提高系统的【安全】防御系数。由于信息安全涉及的需求比较多,今天只给大家介绍一下【审计日志】的需求和具体应用,其他的需求以后再给大家介绍。【审计日志】,简单的说,系统需要记录谁,什么时间,对什么数据做了什么改动!这份日志数据极其珍贵,如果后期业务运营出现问题,可以很方便的进行运营回顾。同时,如果有什么IT系统需要审计,这个任务基本上是必填项目!好了,需求说清楚了,具体应用如下图!2.在实践中实现【审计日志】的需求,我们有一个很好的技术方案,就是利用Spring的切面编程,创建一个代理类,使用afterReturning和afterThrowing方法来记录日志。具体实现步骤如下首先创建审计日志表CREATETABLE`tb_audit_log`(`id`bigint(20)NOTNULLCOMMENT'审计日志,主键ID',`table_name`varchar(500)DEFAULT''COMMENT'操作的表名,多个以逗号分隔',`operate_desc`varchar(200)DEFAULT''COMMENT'操作描述',`request_param`varchar(200)DEFAULT''COMMENT'请求参数',`result`int(10)COMMENT'执行结果,0:成功,1:失败',`ex_msg`varchar(200)DEFAULT''COMMENT'异常信息',`user_agent`textCOLLATEutf8mb4_unicode_ciCOMMENT'用户代理信息',`ip_address`varchar(32)NOTNULLDEFAULT''COMMENT'运行期间的设备IP',`ip_address_name`varchar(32)DEFAULT''COMMENT'运行期间的设备IP地址',`operate_time`datetimeNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'运行时间',`operate_user_id`varchar(32)DEFAULT''COMMENT'operatorID',`operate_user_name`varchar(32)DEFAULT''COMMENT'operator',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_unicode_ciCOMMENT='审计日志表';然后写一个注解类@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD})@Documentedpublic@interfaceSystemAuditLog{/***操作的表名*@return*/StringtableName()default"";/***日志描述*@return*/Stringdescription()default"";}然后写一个Proxy类@Component@AspectpublicclassSystemAuditLogAspect{@AutowiredprivateSystemAuditLogServicesystemAuditLogService;/***定义入口点,切入所有标有该注解的类和方法*/@Pointcut("@within(com.example.demo.core.annotation.SystemAuditLog)||@annotation(com.example.demo.core.annotation.SystemAuditLog)")publicvoidmethodAspect(){}/***在方法调用前拦截*/@Before("methodAspect()")publicvoidbefore(){System.out.println("SystemAuditLogProxy->在调用方法执行之前...");}/***方法调用后拦截*/@After("methodAspect()")publicvoidafter(){System.out.println("SystemAuditLogProxy->Aftercallingmethodexecution...");}/***调用方法结束拦截*/@AfterReturning(value="methodAspect()")publicvoidafterReturning(JoinPointjoinPoint)throwsException{System.out.println("SystemAuditLogProxy->Callmethodendintercept...");//封装数据AuditLogentity=warpAuditLog(joinPoint);实体.setResult(0);//插入数据库systemAuditLogService.add(entity);}/***抛出异常拦截*/@AfterThrowing(value="methodAspect()",throwing="ex")publicvoidafterThrowing(JoinPointjoinPoint,Exceptionex)throwsException{System.out.println("SystemAuditLogProxy->抛出异常拦截...");//封装数据AuditLogentity=warpAuditLog(joinPoint);实体.setResult(1);//封装错误信息entity.setExMsg(ex.getMessage());//插入数据库systemAuditLogService.add(entity);}/***封装插入的实体*@paramjoinPoint*@return*@throwsException*/privateAuditLogwarpAuditLog(JoinPointjoinPoint)throwsException{//获取请求上下文HttpServletRequestrequest=getHttpServletRequest();//获取注解上的参数值SystemAuditLogsystemAuditLog=getServiceMethodDescription(joinPoint);//获取请求参数ObjectrequestObj=getServiceMethodParams(joinPoint);//封装数据AuditLogauditLog=newAuditLog();auditLog.setId(SnowflakeIdWorker.getInstance().nextId());//从请求上下文对象中获取对应的数据if(Objects.nonNull(request)){auditLog.setUserAgent(request.getHeader("User-Agent"));//获取登录时的ip地址auditLog.setIpAddress(IpAddressUtil.getIpAddress(request));//调用外部接口获取IP位置auditLog.setIpAddressName(IpAddressUtil.getLoginAddress(auditLog.getIpAddress()));}//封装操作的表和描述if(Objects.nonNull(systemAuditLog)){auditLog.setTableName(systemAuditLog.tableName());auditLog.setOperateDesc(systemAuditLog.description());}//封装请求参数auditLog.setRequestParam(JSON.toJSONString(requestObj));//封装请求者if(Objects.nonNull(requestObj))&&;requestObjinstanceofBaseRequest){auditLog.setOperateUserId(((BaseRequest)requestObj).getLoginUserId());auditLog.setOperateUserName(((BaseRequest)requestObj).getLoginUserName());审计日志;/***获取当前请求*如果这里报空指针异常,是因为单独使用spring获取请求*需要在配置文件中添加监听**如果是spring项目,通过以下方式注入*
