Browse Source

feat: add user login log (#126)

* feat: add user login log

* fix: checkstyle
master
vran 3 years ago
committed by GitHub
parent
commit
489182f7f5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java
  2. 15
      api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java
  3. 16
      api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java
  4. 14
      api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java
  5. 10
      api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java
  6. 1
      core/src/main/java/com/databasir/core/domain/log/annotation/Operation.java
  7. 51
      core/src/main/java/com/databasir/core/domain/log/service/OperationLogService.java

7
api/src/main/java/com/databasir/api/config/oauth2/DatabasirOauth2LoginFilter.java

@ -1,8 +1,9 @@
package com.databasir.api.config.oauth2;
import com.databasir.api.config.security.DatabasirUserDetailService;
import com.databasir.core.domain.user.data.UserDetailResponse;
import com.databasir.core.domain.app.OpenAuthAppService;
import com.databasir.core.domain.log.service.OperationLogService;
import com.databasir.core.domain.user.data.UserDetailResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
@ -33,6 +34,9 @@ public class DatabasirOauth2LoginFilter extends AbstractAuthenticationProcessing
@Autowired
private DatabasirUserDetailService databasirUserDetailService;
@Autowired
private OperationLogService operationLogService;
public DatabasirOauth2LoginFilter(AuthenticationManager authenticationManager,
OAuth2AuthenticationSuccessHandler auth2AuthenticationSuccessHandler,
AuthenticationFailureHandler authenticationFailureHandler) {
@ -50,6 +54,7 @@ public class DatabasirOauth2LoginFilter extends AbstractAuthenticationProcessing
UserDetails details = databasirUserDetailService.loadUserByUsername(userDetailResponse.getUsername());
DatabasirOAuth2Authentication authentication = new DatabasirOAuth2Authentication(details);
if (!userDetailResponse.getEnabled()) {
operationLogService.saveLoginFailedLog(userDetailResponse.getUsername(), "用户被禁用");
throw new DisabledException("账号已禁用");
}
authentication.setAuthenticated(true);

15
api/src/main/java/com/databasir/api/config/oauth2/OAuth2AuthenticationSuccessHandler.java

@ -2,11 +2,12 @@ package com.databasir.api.config.oauth2;
import com.databasir.api.config.security.DatabasirUserDetails;
import com.databasir.common.JsonData;
import com.databasir.core.domain.login.data.LoginKeyResponse;
import com.databasir.core.domain.log.service.OperationLogService;
import com.databasir.core.domain.login.data.UserLoginResponse;
import com.databasir.core.domain.login.service.LoginService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
@ -21,22 +22,30 @@ import java.nio.charset.StandardCharsets;
@Component
@RequiredArgsConstructor
@Slf4j
public class OAuth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final LoginService loginService;
private final ObjectMapper objectMapper;
private final OperationLogService operationLogService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
DatabasirUserDetails details = (DatabasirUserDetails) authentication.getPrincipal();
LoginKeyResponse loginKey = loginService.generate(details.getUserPojo().getId());
loginService.generate(details.getUserPojo().getId());
UserLoginResponse data = loginService.getUserLoginData(details.getUserPojo().getId())
.orElseThrow(() -> new CredentialsExpiredException("请重新登陆"));
.orElseThrow(() -> {
operationLogService.saveLoginLog(details.getUserPojo(), false, null);
return new CredentialsExpiredException("请重新登陆");
});
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
objectMapper.writeValue(response.getWriter(), JsonData.ok(data));
operationLogService.saveLoginLog(details.getUserPojo(), true, null);
}
}

16
api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationFailureHandler.java

@ -2,8 +2,10 @@ package com.databasir.api.config.security;
import com.databasir.common.JsonData;
import com.databasir.core.domain.app.exception.DatabasirAuthenticationException;
import com.databasir.core.domain.log.service.OperationLogService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.BadCredentialsException;
@ -20,37 +22,51 @@ import java.nio.charset.StandardCharsets;
@Component
@RequiredArgsConstructor
@Slf4j
public class DatabasirAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final ObjectMapper objectMapper;
private final OperationLogService operationLogService;
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String username = request.getParameter("username");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
if (exception instanceof BadCredentialsException) {
JsonData<Void> data = JsonData.error("-1", "用户名或密码错误");
saveLoginFailedLog(username, data.getErrMessage());
String jsonString = objectMapper.writeValueAsString(data);
response.setStatus(HttpStatus.OK.value());
response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8));
} else if (exception instanceof DisabledException) {
JsonData<Void> data = JsonData.error("-1", "用户已禁用");
saveLoginFailedLog(username, data.getErrMessage());
String jsonString = objectMapper.writeValueAsString(data);
response.setStatus(HttpStatus.OK.value());
response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8));
} else if (exception instanceof DatabasirAuthenticationException) {
DatabasirAuthenticationException bizException = (DatabasirAuthenticationException) exception;
JsonData<Void> data = JsonData.error(bizException.getErrCode(), bizException.getErrMessage());
saveLoginFailedLog(username, data.getErrMessage());
String jsonString = objectMapper.writeValueAsString(data);
response.setStatus(HttpStatus.OK.value());
response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8));
} else {
JsonData<Void> data = JsonData.error("-1", "未登录或未授权用户");
saveLoginFailedLog(username, data.getErrMessage());
String jsonString = objectMapper.writeValueAsString(data);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getOutputStream().write(jsonString.getBytes(StandardCharsets.UTF_8));
}
}
private void saveLoginFailedLog(String username, String message) {
if (username != null) {
operationLogService.saveLoginFailedLog(username, message);
}
}
}

14
api/src/main/java/com/databasir/api/config/security/DatabasirAuthenticationSuccessHandler.java

@ -1,11 +1,12 @@
package com.databasir.api.config.security;
import com.databasir.common.JsonData;
import com.databasir.core.domain.login.data.LoginKeyResponse;
import com.databasir.core.domain.log.service.OperationLogService;
import com.databasir.core.domain.login.data.UserLoginResponse;
import com.databasir.core.domain.login.service.LoginService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
@ -20,12 +21,15 @@ import java.nio.charset.StandardCharsets;
@Component
@RequiredArgsConstructor
@Slf4j
public class DatabasirAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final ObjectMapper objectMapper;
private final LoginService loginService;
private final OperationLogService operationLogService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
@ -34,9 +38,13 @@ public class DatabasirAuthenticationSuccessHandler implements AuthenticationSucc
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
LoginKeyResponse loginKey = loginService.generate(user.getUserPojo().getId());
loginService.generate(user.getUserPojo().getId());
UserLoginResponse data = loginService.getUserLoginData(user.getUserPojo().getId())
.orElseThrow(() -> new CredentialsExpiredException("请重新登陆"));
.orElseThrow(() -> {
operationLogService.saveLoginLog(user.getUserPojo(), false, null);
return new CredentialsExpiredException("请重新登陆");
});
operationLogService.saveLoginLog(user.getUserPojo(), true, null);
objectMapper.writeValue(response.getWriter(), JsonData.ok(data));
}
}

10
api/src/main/java/com/databasir/api/config/security/DatabasirUserDetailService.java

@ -1,10 +1,12 @@
package com.databasir.api.config.security;
import com.databasir.core.domain.log.service.OperationLogService;
import com.databasir.dao.impl.UserDao;
import com.databasir.dao.impl.UserRoleDao;
import com.databasir.dao.tables.pojos.UserPojo;
import com.databasir.dao.tables.pojos.UserRolePojo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@ -15,16 +17,22 @@ import java.util.List;
@Service
@RequiredArgsConstructor
@Slf4j
public class DatabasirUserDetailService implements UserDetailsService {
private final UserDao userDao;
private final UserRoleDao userRoleDao;
private final OperationLogService operationLogService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserPojo user = userDao.selectByEmailOrUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("用户名或密码错误"));
.orElseThrow(() -> {
operationLogService.saveLoginFailedLog(username, "用户名不存在");
return new UsernameNotFoundException("用户名或密码错误");
});
List<UserRolePojo> roles = userRoleDao.selectByUserIds(Collections.singletonList(user.getId()));
return new DatabasirUserDetails(user, roles);
}

1
core/src/main/java/com/databasir/core/domain/log/annotation/Operation.java

@ -36,6 +36,7 @@ public @interface Operation {
String LOGIN_APP = "login_app";
String SETTING = "setting";
String DATABASE_TYPE = "database_type";
String LOGIN = "login";
}
interface Types {

51
core/src/main/java/com/databasir/core/domain/log/service/OperationLogService.java

@ -1,5 +1,7 @@
package com.databasir.core.domain.log.service;
import com.databasir.common.JsonData;
import com.databasir.core.domain.log.annotation.Operation;
import com.databasir.core.domain.log.converter.OperationLogPojoConverter;
import com.databasir.core.domain.log.converter.OperationLogRequestConverter;
import com.databasir.core.domain.log.data.OperationLogPageCondition;
@ -14,17 +16,20 @@ import com.databasir.dao.tables.pojos.OperationLogPojo;
import com.databasir.dao.tables.pojos.ProjectPojo;
import com.databasir.dao.tables.pojos.UserPojo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class OperationLogService {
private final OperationLogDao operationLogDao;
@ -44,6 +49,52 @@ public class OperationLogService {
return operationLogDao.insertAndReturnId(pojo);
}
public void saveLoginFailedLog(String username, String msg) {
try {
JsonData result = JsonData.error("-1", Objects.requireNonNullElse(msg, "登录失败"));
OperationLogRequest log = OperationLogRequest.builder()
.isSuccess(false)
.operationCode("login")
.operationModule(Operation.Modules.LOGIN)
.operationName("登录")
.operatorNickname(username)
.operatorUsername(username)
.operatorUserId(-1)
.operationResponse(result)
.build();
OperationLogPojo pojo = operationLogRequestConverter.toPojo(log);
operationLogDao.insertAndReturnId(pojo);
} catch (Exception e) {
log.error("保存登录日志失败", e);
}
}
public void saveLoginLog(UserPojo user, Boolean success, String msg) {
try {
JsonData result;
if (success) {
result = JsonData.ok();
} else {
result = JsonData.error("-1", Objects.requireNonNullElse(msg, "登录失败"));
}
OperationLogRequest log = OperationLogRequest.builder()
.isSuccess(success)
.involvedUserId(user.getId())
.operationCode("login")
.operationModule(Operation.Modules.LOGIN)
.operationName("登录")
.operatorNickname(user.getNickname())
.operatorUsername(user.getUsername())
.operatorUserId(user.getId())
.operationResponse(result)
.build();
OperationLogPojo pojo = operationLogRequestConverter.toPojo(log);
operationLogDao.insertAndReturnId(pojo);
} catch (Exception e) {
log.error("保存登录日志失败", e);
}
}
public Page<OperationLogPageResponse> list(Pageable page,
OperationLogPageCondition condition) {
Page<OperationLogPojo> pojoData = operationLogDao.selectByPage(page, condition.toCondition());

Loading…
Cancel
Save