Commit 02a06796 authored by 向怀芳's avatar 向怀芳 🎱

1. 添加审计日志处理

parent 0c1c5938
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationFailureEvenHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationFailureEvenHandler extends AbstractAuthenticationFailureEvenHandler {
/**
* 处理登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
*/
@Override
public void handle(AuthenticationException authenticationException, Authentication authentication) {
log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
*
* 登录操作次数锁定功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler {
private final RedisTemplate<String, String> redisTemplate;
private final RemoteUserService remoteUserService;
/**
* 密码错误超过 5 此自动锁定
* <p>
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
// 只处理账号密码错误异常
if (!(authenticationException instanceof BadCredentialsException)) {
return;
}
String username = authentication.getName();
String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long deltaTimes = 5L;
Long times = redisTemplate.opsForValue().increment(key);
// 自动过期时间
Long deltaTime = 30L;
redisTemplate.expire(key, deltaTime, TimeUnit.MINUTES);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLogEventHandler implements AuthenticationFailureHandler {
private final RemoteLogService logService;
/**
* 异步处理,登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
sysLog.setException(authenticationException.getLocalizedMessage());
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录失败,异常:{}", username, authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 退出事件处理
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationLogoutEventHandler implements AuthenticationLogoutHandler {
private final RemoteLogService logService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登出");
sysLog.setParams(username);
// 获取clientId 信息
OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
// 保存退出的token
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
sysLog.setParams(token);
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 退出成功, token:{} 已注销", username, token);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationSuccessEventHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
*/
@Override
public void handle(Authentication authentication) {
log.info("用户:{} 登录成功", authentication.getPrincipal());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录操作次数锁定清楚功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLockEventHandler implements AuthenticationSuccessHandler {
private final RedisTemplate<String, String> redisTemplate;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
// String username = authentication.getName();
// String key = String.format("%s:%s:%s", CacheConstants.LOGIN_ERROR_TIMES, tenantKeyStrResolver.key(), username);
// redisTemplate.delete(key);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录成功日志记录
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLogEventHandler implements AuthenticationSuccessHandler {
private final RemoteLogService remoteLogService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录成功", username);
}
}
......@@ -8,75 +8,34 @@ package cn.sh.stc.sict.cloud.common.core.constant;
*/
public class RedisCacheConstant {
/**
* 用户角色与终端类型的分隔符
* 用户角色与终端类型的分隔符
*/
public static final String USER_ROLE_SEPARATOR = "@";
/**
* 微信用户信息明细
*/
public static final String WX_USER_DETAILS = "wx_user_details";
/**
* 基础用户信息明细 base
*/
public static final String BASE_USER_DETAILS = "base_user_details";
/**
* 基础学生信息
*/
public static final String CURRENT_STUDENT = "current_student";
public static final String APP = "hpgp:";
/**
* 基础用户信息明细
*/
public static final String USER_DETAILS = "user_details";
public static final String USER_DETAILS = APP + "user_details";
/**
* 当前登录用户的角色信息
*/
public static final String TOKEN_ROLES = "token_roles";
public static final String TOKEN_ROLES = APP + "token_roles";
/**
* 当前登录用户的详细信息
*/
public static final String TOKEN_CURRENT = "token_current";
/**
* 微信应用缓存
*/
public static final String WECHAT_OFFICALS = "wechat_officals";
/**
* 冷知识点赞数量
*/
public static final String CLD_TRIVIA_NUM = "cld_trivia_num";
/**
* 积分
*/
public static final String CREDIT = "credit";
public static final String CREDIT_NEXT_LEVEL_BY_SCORE = "credit:score:next";
public static final String CREDIT_LEVEL_BY_SCORE = "credit:score:current";
/**
* 未付款订单
*/
public static final String PAY_ORDER_NOT_PAID = "order_info:not_paid";
/**
* temp 微信支付开关
*/
public static final String WECHAT_APPLE_PAY_SWITCH = "order_info:wechat_apple_pay_switch";
/**
* 是否需要弹窗
*/
public static final String WECHAT_POP_UP = "pop-up:kindergarten";
public static final String TOKEN_CURRENT = APP + "token_current";
/**
* /**
* 用户短信验证码
*/
public static final String SICT_PHONE_CODE_KEY = "SICT_PHONE_CODE_KEY";
public static final String SICT_PHONE_CODE_KEY = APP + "SICT_PHONE_CODE_KEY";
/**
* 路由存放
*/
public static final String ROUTE_KEY = "hp_gateway_route_key";
public static final String ROUTE_KEY = APP + "hp_gateway_route_key";
/**
* 验证码前缀
*/
public static final String DEFAULT_CODE_KEY = "SICT_DEFAULT_CODE_KEY_";
public static final String DEFAULT_CODE_KEY = APP + "SICT_DEFAULT_CODE_KEY_";
public static final String LOGIN_ERROR_TIMES = APP + "login_error_times";
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationFailureHandler {
/**
* 业务处理
* @param authenticationException 错误信息
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationLogoutHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationSuccessHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationFailureEventListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {
@Autowired(required = false)
private List<AuthenticationFailureHandler> failureHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
// 此类型事件不传递处理 #2386
if (event instanceof AuthenticationFailureProviderNotFoundEvent) {
return;
}
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
AuthenticationException authenticationException = event.getException();
Authentication authentication = (Authentication) event.getSource();
// 调用自定义业务链实现
if (CollUtil.isNotEmpty(failureHandlerList)) {
failureHandlerList.forEach(failureHandler -> failureHandler.handle(authenticationException, authentication,
request, response));
}
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AuthenticationLogoutSuccessEventListener implements ApplicationListener<AbstractAuthenticationEvent> {
@Autowired(required = false)
private AuthenticationLogoutHandler logoutHandler;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationEvent event) {
// 健壮性判断
if (!(event.getSource() instanceof OAuth2Authentication)) {
return;
}
OAuth2Authentication authentication = (OAuth2Authentication) event.getSource();
if (logoutHandler != null && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
logoutHandler.handle(authentication, request, response);
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationSuccessEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
@Autowired(required = false)
private List<AuthenticationSuccessHandler> successHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
Authentication authentication = (Authentication) event.getSource();
if (CollUtil.isNotEmpty(successHandlerList) && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
successHandlerList.forEach(successHandler -> successHandler.handle(authentication, request, response));
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
......@@ -57,6 +57,19 @@ public class SysLogUtils {
return sysLog;
}
public SysLog getSysLog(HttpServletRequest request, String username) {
SysLog sysLog = new SysLog();
sysLog.setCreateBy(username);
sysLog.setType(Constant.BYTE_NO);
sysLog.setRemoteAddr(ServletUtil.getClientIP(request));
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
sysLog.setMethod(request.getMethod());
sysLog.setUserAgent(request.getHeader("user-agent"));
sysLog.setParams(HttpUtil.toParams(request.getParameterMap()));
sysLog.setServiceId("/cloud-auth");
return sysLog;
}
public static Map<String, Object> getKeyAndValue(Object obj) {
Map<String, Object> map = new HashMap<>();
try {
......
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\
cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl,\
cn.sh.stc.sict.cloud.common.security.component.SictWebResponseExceptionTranslator,\
cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationFailureEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationSuccessEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationLogoutSuccessEventListener
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment