我一直致力于应用程序审计,并已成功连接Hibernate Envers 4.3.11以捕获创建,更新和删除,但我找不到任何有关实体审计读取的文档。
这可能与Envers一起使用还是最好依赖log4j或类似的?
我相信它不可能。我们有类似的用例,我们使用拦截器来生成我们服务的审计记录。
是的,Hibernate Envers可以审核实体的读取。以下是从第一次修订的审计表中读取记录的示例。
/*Audit Reader*/
public AuditReader getAuditReader() {
return AuditReaderFactory.get(getCrntSession());
}
/*The method to read a record from an entity*/
Integer revisionNumber = (Integer) getAuditReader().createQuery()
.forRevisionsOfEntity(Employee.class, false, true)
.addProjection(AuditEntity.revisionNumber().min())
.getSingleResult();
AuditReader reader = getAuditReader();
Employee emp=reader.findRevision(Employee.class, (Number)revisionNumber);
/* and if Employee has an createdDate record , we can read it using below*/:
System.out.println(emp.getCreatedDate());
这是记录读取的内容。一段时间过去了,所以我可能会错过一个细节,但我认为这就是一切。
这是一个Envers RevisionListener
实现。它获取IP地址和经过身份验证的用户名,并创建在每次读取时写入数据库的实体。
package com.example.audit;
import javax.servlet.http.HttpServletRequest;
import org.hibernate.envers.RevisionListener;
import com.example.utilities.RequestUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
public class UserRevisionListener implements RevisionListener {
@Override
public void newRevision(Object revisionEntity) {
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Assert.notNull(auth, "Could not find an Authentication object for this user");
Assert.notNull(auth.getPrincipal(), "Principal must not be null.");
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes();
Assert.notNull(servletRequestAttributes, "Current request attributes was null, remote address not attainable");
HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
Assert.notNull(httpServletRequest, "Request was null, remote address not attainable");
String remoteAddress = RequestUtils.getClientIpAddr(httpServletRequest);
Assert.notNull(remoteAddress, "Remote address was null");
String username = ((UserDetails) auth.getPrincipal()).getUsername();
Assert.notNull(username, "Could not audit record due to missing username");
UserRevisionEntity userRevisionEntity = (UserRevisionEntity) revisionEntity;
userRevisionEntity.setUsername(username);
userRevisionEntity.setIp(remoteAddress);
}
}
这是Hibernate实体:
package com.example.audit;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.ModifiedEntityNames;
import org.hibernate.envers.RevisionEntity;
@Entity
@RevisionEntity(UserRevisionListener.class)
public class UserRevisionEntity extends DefaultRevisionEntity {
private static final long serialVersionUID = -3922860601141228497L;
private String username;
private String ip;
@ElementCollection
@JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV"))
@Column(name = "ENTITYNAME")
@ModifiedEntityNames
private Set<String> modifiedEntityNames;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
这是RequestUtils.java
:
package com.example.utilities;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.Assert;
public final class RequestUtils {
private static final String UNKNOWN = "unknown";
private RequestUtils() {
}
/**
* If any proxy or load balancer exists between the client and the server {@link HttpServletRequest#getRemoteAddr()}
* will return localhost or the address of the middle machine.
*
* @param request
* a {@link HttpServletRequest}
* @return The remote address of the client accessing the server.
*/
public static String getClientIpAddr(HttpServletRequest request) {
Assert.notNull(request, "Request must not be null");
return Stream
.of("X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP",
"HTTP_X_FORWARDED_FOR")
.filter(header -> validHeader(header, request))
.map(header -> request.getHeader(header))
.findFirst()
.orElse(request.getRemoteAddr());
}
private static Boolean validHeader(String header, HttpServletRequest request) {
String ip = request.getHeader(header);
return !(ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip));
}
}
它需要以下属性:
spring.jpa.properties.org.hibernate.envers.audit_table_suffix=_audit
spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true
spring.jpa.properties.org.hibernate.envers.audit_strategy=org.hibernate.envers.strategy.ValidityAuditStrategy
spring.jpa.properties.org.hibernate.envers.audit_strategy_validity_store_revend_timestamp=true
spring.jpa.properties.org.hibernate.envers.track_entities_changed_in_revision=true