監査ログ
定義:何時間何もしませんでした、。
場所:認証した後、承認の前に。
あなたがアクセスしている人知っているので、アクセスの拒否もオフレコことができます。認証の前に置か場合は、アクセスしているか分からない。承認後に置かれた場合、そのレコードにアクセスする方法は拒否されません。
ストレージ:監査ログは永続的でなければならない、メモリ内のデータベースまたはファイルに記録が失われます。(ログサービス会社への出力)
どのように心:要求がレコードの時間、要求時間のうち、更新ログに来ました。
要求が入ってきたときにだけ覚えていれば、その要求は成功するかどうか分からないです。あなただけのリクエストが返されるときに覚えている場合は、あなたが構築して電話を切った場合、要求は、ぶらぶらされるか分からない、覚えていませんでした。
技術的なオプション:フィルタ VS迎撃 VS ControllerAdvice VS AOP
フィルターは、良好な解像度は、実装や要求の実行から出てくるための要求であり、 ControllerAdvice-は、グローバルな例外ハンドラを行い、AOP -言いません
インターセプター使用するには、インターセプターは、フィルタの後に行われます。
制限フィルタは、第1の制御を行う、@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
+++++++++++++++++++++分割线++++++++++++++++++++++++++++++
小结
本篇说了什么是审计,审计在代码中的位置,以及用拦截器来实现审计