feat: add user login log (#126)
* feat: add user login log * fix: checkstyle
This commit is contained in:
parent
d0a7a25a4d
commit
489182f7f5
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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…
Reference in New Issue