在我们的微服务架构中,我们正在将用户活动记录到mongo数据库表中?有什么好的方法来存储和检索审核日志吗?
答案 0 :(得分:0)
通过使用DAO模式将AuditLogging存储到Mongo数据库中,您可以想到与以下类似的解决方案。
@Entity
@Table(name = "AuditLogging")
public class AuditLogging implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "auditid", updatable = false, nullable = false)
private Long auditId;
@Column(name = "event_type", length = 100)
@Enumerated(EnumType.STRING)
private AuditingEvent event;
@Column(name = "event_creator", length = 100)
@Enumerated(EnumType.STRING)
private EventCreator eventCreator;
@Column(name = "adminid", length = 20)
private String adminId;
@Column(name = "userid", length = 20)
private String userId;
@Column(name = "event_date")
private Date eventDate;
}
public class Constants {
public static final String EVENT_TYPE = "eventType";
public static final String EVENT_CREATOR = "eventCreator";
public static final String NEW_EMAIL_ID = "newEmailId";
public static final String OLD_EMAIL_ID = "oldEmailId";
}
public enum AuditEvent {
USER_REGISTRATION,
USER_LOGIN,
USER_LOGIN_FAIL,
USER_ACCOUNT_LOCK,
USER_LOGOFF,
USER_PASSWORD_CHANGE,
USER_PASSWORD_CHANGE_FAIL,
USER_FORGOT_PASSWORD,
USER_FORGOT_PASSWORD_FAIL,
ADMIN_LOGIN
}
public enum EventCreator {
ADMIN_FOR_SELF,
USER_FOR_SELF,
ADMIN_FOR_USER
}
public interface AuditingDao {
/**
* Stores the event into the DB/Mongo or Whatever
*
* @param auditLogging
* @return Boolean status
*/
Boolean createAuditLog(final AuditLogging auditLogging);
/* Returns the log occurrence of a specific event
*
* @param event
* @return List of logged events by type
*/
List<AuditLogging> getLogsForEvent(final AuditingEvent event);
}
public interface AuditingService {
/**
* Creates an Audit entry in the AuditLogging table using the
* DAO layer
*
* @param auditingEvent
* @param eventCreator
* @param userId
* @param adminId *
* @return {@link Boolean.TRUE} for success and {@link Boolean.FALSE} for
* failure
*/
Boolean createUserAuditEvent(final AuditEvent auditEvent,
final EventCreator eventCreator, final String userId, final String adminId,
final String newEmailId,final String oldEmailId);
/**
*
* Returns all event for a user/admin based on the id
*
* @param id
* @return List of logged events for an id
*/
List<AuditLogging> fetchLoggedEventsById(final String id);
/***
* Returns all event based on event type
*
* @param eventName
* @return List of logged events for an event
*/
List<AuditLogging> fetchLoggedEventsByEventName(final String eventName);
}
@Service("auditingService")
public class AuditServiceImpl implements AuditingService {
@Autowired
private AuditingDao auditingDao;
private static Logger log = LogManager.getLogger();
@Override
public Boolean createUserAuditingEvent(AuditEvent auditEvent,
EventCreator eventCreator, String userId, String adminId,
String newEmailId,String oldEmailId) {
AuditLogging auditLogging = new AuditLogging();
auditLogging.setEvent(auditingEvent);
auditLogging.setEventCreator(eventCreator);
auditLogging.setUserId(userId);
auditLogging.setAdminId(adminId);
auditLogging.setEventDate(new Date());
return Boolean.TRUE;
}
@Override
public List<AuditLogging> fetchLoggedEventsByEventName(
final String eventName) {
AuditEvent event = null;
try {
event = AuditingEvent.valueOf(eventName);
} catch (Exception e) {
log.error(e);
return Collections.emptyList();
}
return auditingDao.getLogsForEvent(event);
}
public void setAuditingDao(AuditingDao auditingDao) {
this.auditingDao = auditingDao;
}
}
通过指向适当的控制器方法来触发事件,编写方面对于此类情况总是有利的。
@Aspect
@Component("auditingAspect")
public class AuditingAspect {
@Autowired
AuditingService auditingService;
/* The below controllers you can think of your microservice endpoints
*/
@Pointcut("execution(* com.controller.RegistrationController.authenticateUser(..)) ||execution(* com.controller.RegistrationController.changeUserPassword(..)) || execution(* com.controller.RegistrationController.resetPassword(..)) ||execution(* com.controller.UpdateFunctionalityController.updateCustomerDetails(..))")
public void aroundPointCut() {}
@Around("aroundPointCut()")
public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint)
throws Throwable {
joinPoint.getSignature().getName();
joinPoint.getArgs();
// auditingService
Object result = joinPoint.proceed();
ResponseEntity entity = (ResponseEntity) result;
HttpServletRequest request =
((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
if(!((request.getAttribute(Constants.EVENT_TYPE).toString()).equalsIgnoreCase(AuditEvent.USER_LOGIN.toString()) || (((request.getAttribute(Constants.EVENT_TYPE).toString()).equalsIgnoreCase(AuditEvent.ADMIN_LOGIN.toString()))))){
auditingService.createUserAuditEvent(
(AuditingEvent) request.getAttribute(Constants.EVENT_TYPE),
(EventCreator) request.getAttribute(Constants.EVENT_CREATOR),
(request.getAttribute(Constants.USER_ID)!= null ? request.getAttribute(Constants.USER_ID).toString():""), null,
(request.getAttribute(Constants.NEW_EMAIL_ID) == null ? ""
: request.getAttribute(Constants.NEW_EMAIL_ID).toString()),
(request.getAttribute(Constants.OLD_EMAIL_ID) == null ? ""
: request.getAttribute(Constants.OLD_EMAIL_ID).toString()));
}
return entity;
}
}
从REST控制器中,Aspect找到相应的事件时将被触发。
@RestController
public class RegistrationController {
@RequestMapping(path = "/authenticateUser", method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
/* This method call triggers the aspect */
@ResponseBody
public ResponseEntity<String> authenticateUser(HttpServletRequest request, @RequestBody User user)
throws Exception {
request.setAttribute(Constants.EVENT_TYPE, AuditingEvent.USER_LOGIN);
request.setAttribute(Constants.EVENT_CREATOR, EventCreator.USER_FOR_SELF);
request.setAttribute(Constants.USER_ID, user.getUserId());
ResponseEntity<String> responseEntity = null;
try {
// Logic for authentication goes here
responseEntity = new ResponseEntity<>(respData, HttpStatus.OK);
} catch (Exception e) {
request.setAttribute(Constants.EVENT_TYPE, AuditEvent.USER_LOGIN_FAIL);
responseEntity = new ResponseEntity<>(respData, HttpStatus.INTERNAL_SERVER_ERROR);
}
return responseEntity;
}
}
我希望这个答案有意义,并且您也可以为Mongo实现类似的功能。
干杯!