• Spring Cloud微服务安全实战_3-6_API安全机制之审计


    审计日志

    定义:谁,在什么时间,干了什么事。

    位置:认证之后,授权之前。

       这样就知道是谁在访问,拒绝掉的访问也能被记录。如果放在认证之前,那么就不知道是谁在访问;如果放在授权之后,就没办法记录被拒绝的访问。

    存储:审计日志一定要持久化,记在数据库里或者是文件,放在内存会丢失。(输出到公司的日志服务)

    怎么记:请求进来的时候记录一次,请求出去的时候,更新日志。

        如果只在请求进来的时候记,那么请求的成功与否是不知道的。如果只在请求返回的时候记,那么如果一个请求把你的系统搞挂了,也没有记,是不知道谁搞挂的。

    技术选择:过滤器 VS 拦截器  VS ControllerAdvice VS AOP

           过滤器,不好分辨是请求过来执行的还是请求出去执行的; ControllerAdvice-做全局异常处理 ;AOP -不说了

                     就用拦截器,拦截器在过滤器之后执行。

     限流过滤器用 @Order注解,控制在第一个执行

     认证过滤器,排在老二位置:

    再写个审计拦截器,就是过滤器之后执行了

    实现

    数据库

     实体类:

    /**
     * <p>
     * 审计日志
     * </p>
     *
     * @author 李浩洋
     * @since 2019-10-27
     */
    @Data
    public class AuditLog implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private Long id;
    
        /**
         * http方法
         */
        private String method;
    
        /**
         * 请求路径
         */
        private String path;
    
        /**
         * http状态码
         */
        private Integer status;
    
        /**
         * 请求用户名
         */
        private String username;
    
        /**
         * 创建时间
         */
        private Date createTime;
    
        /**
         * 修改时间
         */
        private Date updateTime;
    
    
    }

    审计拦截器:

    package com.nb.security.interceptor;
    
    import com.nb.security.entity.AuditLog;
    import com.nb.security.entity.User;
    import com.nb.security.service.IAuditLogService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.lang.Nullable;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Date;
    
    /**
     * 审计日志拦截器
     * 拦截流程
     * 流控 -- 认证 --审计 -- 授权 -- 业务
     * 审计要在进入接口之前,insert 数据库(实际可能发送到专门的日志服务器),执行完后 update,过滤器不便于判断拦截之前、之后,故用拦截器
     */
    @Component
    public class AuditLogInterceptor extends HandlerInterceptorAdapter {
    
        @Autowired
        private IAuditLogService auditLogService;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            AuditLog log = new AuditLog();
            log.setMethod(request.getMethod());
            log.setPath(request.getRequestURI());
            log.setCreateTime(new Date());
    
            User user = (User) request.getAttribute("user");
            if (user != null) {
                user.setUsername(user.getUsername());
            }
            auditLogService.save(log);
    
            //将审计日志的id传给request,以便于请求处理完成后更新审计日志
            request.setAttribute("auditLogId", log.getId());
    
            return super.preHandle(request, response, handler);
        }
    
    
        /**
         * 请求处理成功失败,都更新审计日志
         *
         * @param request
         * @param response
         * @param handler
         * @param ex
         * @throws Exception
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
            //审计日志id
            Long auditLogId = (Long) request.getAttribute("auditLogId");
            AuditLog log = auditLogService.getById(auditLogId);
            log.setStatus(response.getStatus());
            log.setUpdateTime(new Date());
            auditLogService.updateById(log);
    
            super.afterCompletion(request, response, handler, ex);
        }
    }

    拦截器配置:

    @Configuration
    public class SecurityConfig implements WebMvcConfigurer {
    
        //审计日志
        @Autowired
        private AuditLogInterceptor auditLogInterceptor;
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(auditLogInterceptor);//.addPathPatterns();//先add的先执行,默认所有请求都拦截
        }
    }

    用Postman来一个正确的请求:

    数据库新增了一条数据

     

     控制台可以看到执行顺序,就是想要的结果。

     错误的访问:

     数据库insert了两条数据,一个是我的请求 /users/12 ,另一个 /error 是SpringBoot抛出异常后,会跳到一个/error 的路径, 

     

     新建一个异常处理器:

     再发一个失败的请求:

     数据库就不会再有 /error 请求了。

    代码:https://github.com/lhy1234/springcloud-security/tree/master/nb-user-api

    +++++++++++++++++++++分割线++++++++++++++++++++++++++++++

    小结

    本篇说了什么是审计,审计在代码中的位置,以及用拦截器来实现审计

  • 相关阅读:
    c++中string类中的函数
    二进制
    快速幂
    substring
    hdu 4678
    扩展欧几里得算法
    欧几里得算法
    Floyd_Warshall(任意两点之间的最短路)
    带结构体的优先队列
    php获得远程信息到本地使用的3个函数:file_get_contents和curl函数和stream_get_contents
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/12005668.html
Copyright © 2020-2023  润新知