SpringCloud微服务安全API安全 2-6 审计

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud微服务安全API安全 2-6 审计相关的知识,希望对你有一定的参考价值。

1. 补充:如何保证API安全的请求流程

当前已经有了流控、认证,但是它们并没有按照要求进行顺序执行。

我们要求先执行流控,然后再执行认证。

解决方案: 使用 @Order注解

流控:

认证:

2. 审计日志

2.1 审计说明

审计日志

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

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

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

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

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

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

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

选择的原因:

  • 过滤器,不好分辨是请求过来执行的还是请求出去执行的; ControllerAdvice-做全局异常处理 ;AOP -不说了
  • 就用拦截器,拦截器在过滤器之后执行

3. 审计功能

3.1 创建审计日志类

package com.imooc.security.log;

import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;

/**
 * @ClassName AuditLog
 * @Description TODO 审计日志
 * @Author wushaopei
 * @Date 2021/5/1 17:56
 * @Version 1.0
 */
@Entity
@Data
@EntityListeners(AuditingEntityListener.class) // 注入审计监听器
public class AuditLog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String method;

    private String path;

    private Integer status;

    private String username;

    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private Date createTime;

    @Temporal(TemporalType.TIMESTAMP)
    @CreatedDate
    private Date modifyTime;
}

这里需要从Java实体反向生成数据库对应的表,需要保证在application.yml中添加以下配置:

jpa:
    generate-ddl: true #控制是否执行datasource.schema脚本,来初始化数据库结构
    show-sql: true

3.2 创建审计拦截器

package com.imooc.security.filter;
import com.imooc.security.log.AuditLog;
import com.imooc.security.log.AuditLogRepository;
import com.imooc.security.user.User;
import org.checkerframework.checker.units.qual.A;
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;
/**
 * @ClassName AuditLogInterceptor
 * @Description TODO 审计日志拦截器
 * @Author wushaopei
 * @Date 2021/5/1 18:02
 * @Version 1.0
 */
@Component
public class AuditLogInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private AuditLogRepository auditLogRepository;

    /**
     * @Description TODO 前置处理,请求进来就进行记录
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        AuditLog log = new AuditLog();
        log.setMethod(request.getMethod());
        log.setPath(request.getRequestURI());
        User user = (User)request.getAttribute("user");
        if (user != null){
            log.setUsername(user.getUsername());
        }
        auditLogRepository.save(log);
        request.setAttribute("auditLogId", log.getId());

        return true;
    }

    /**
     * @Description TODO 后置处理,请求返回的时候进行记录
     * @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 {

        Long auditLogId = (Long)request.getAttribute("auditLogId");
        AuditLog log = auditLogRepository.findById(auditLogId).get();
        log.setStatus(response.getStatus());
        auditLogRepository.save(log);
    }
}

3.3 注册审计拦截器

@Configuration
@EnableJpaAuditing //JPA审计的总开关
public class SecurityConfig implements WebMvcConfigurer {

    @Autowired
    private AuditLogInterceptor auditLogInterceptor;

    /**
     * @Description TODO 将审计拦截器添加到mvc容器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(auditLogInterceptor);
    }
}

3.4 创建审计类写入DB的类  AuditLogRepository.java

public interface AuditLogRepository extends JpaSpecificationExecutor<User>,CrudRepository<AuditLog,Long> {

}

3.5 启动程序自动生成 audit_log 表

3.6 发起请求,拦截器拦截请求并记录到审计日志中

记录审计日志:

3.7 新增异常处理器

解决SpringBoot抛出异常后,会跳到一个/error 的路径。然后将 error 记录到审计日志的问题。

package com.imooc.security.filter;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName ErrorHandler
 * @Description TODO 异常处理类
 * @Author wushaopei
 * @Date 2021/5/1 18:33
 * @Version 1.0
 */
@RestControllerAdvice
public class ErrorHandler {

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public Map<String, Object> handler(Exception e){
        Map<String, Object> info = new HashMap<>();
        info.put("message", e.getMessage());
        info.put("time",new Date().getTime());
        return info;
    }
}

返回异常处理信息给前端:

 

以上是关于SpringCloud微服务安全API安全 2-6 审计的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud微服务安全API安全 2-2 注入攻击防护

SpringCloud微服务安全实战API安全 3-9 总结

SpringCloud微服务安全API安全 2-7 授权

SpringCloud微服务安全实战API安全 3-5 认证

SpringCloud微服务安全API安全 2-8 授权

SpringCloud微服务安全API安全 2-4 认证