1. 统一包名修改
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.framework.operatelog.config;
|
||||
|
||||
import com.zt.plat.framework.operatelog.core.service.LogRecordServiceImpl;
|
||||
import com.mzt.logapi.service.ILogRecordService;
|
||||
import com.mzt.logapi.starter.annotation.EnableLogRecord;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* 操作日志配置类
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦
|
||||
@AutoConfiguration
|
||||
@Slf4j
|
||||
public class CloudOperateLogConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public ILogRecordService iLogRecordServiceImpl() {
|
||||
return new LogRecordServiceImpl();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.zt.plat.framework.operatelog.config;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.logger.OperateLogCommonApi;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* OperateLog 使用到 Feign 的配置项
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableFeignClients(clients = {OperateLogCommonApi.class}) // 主要是引入相关的 API 服务
|
||||
public class CloudOperateLogRpcAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 占位,无特殊作用
|
||||
*/
|
||||
package com.zt.plat.framework.operatelog.core;
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.zt.plat.framework.operatelog.core.service;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.logger.OperateLogCommonApi;
|
||||
import com.zt.plat.framework.common.util.monitor.TracerUtils;
|
||||
import com.zt.plat.framework.common.util.servlet.ServletUtils;
|
||||
import com.zt.plat.framework.security.core.LoginUser;
|
||||
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.zt.plat.framework.common.biz.system.logger.dto.OperateLogCreateReqDTO;
|
||||
import com.mzt.logapi.beans.LogRecord;
|
||||
import com.mzt.logapi.service.ILogRecordService;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 操作日志 ILogRecordService 实现类
|
||||
*
|
||||
* 基于 {@link OperateLogCommonApi} 实现,记录操作日志
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
@Slf4j
|
||||
public class LogRecordServiceImpl implements ILogRecordService {
|
||||
|
||||
@Resource
|
||||
private OperateLogCommonApi operateLogApi;
|
||||
|
||||
@Override
|
||||
public void record(LogRecord logRecord) {
|
||||
OperateLogCreateReqDTO reqDTO = new OperateLogCreateReqDTO();
|
||||
try {
|
||||
reqDTO.setTraceId(TracerUtils.getTraceId());
|
||||
// 补充用户信息
|
||||
fillUserFields(reqDTO);
|
||||
// 补全模块信息
|
||||
fillModuleFields(reqDTO, logRecord);
|
||||
// 补全请求信息
|
||||
fillRequestFields(reqDTO);
|
||||
|
||||
// 2. 异步记录日志
|
||||
operateLogApi.createOperateLogAsync(reqDTO);
|
||||
} catch (Throwable ex) {
|
||||
// 由于 @Async 异步调用,这里打印下日志,更容易跟进
|
||||
log.error("[record][url({}) log({}) 发生异常]", reqDTO.getRequestUrl(), reqDTO, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void fillUserFields(OperateLogCreateReqDTO reqDTO) {
|
||||
// 使用 SecurityFrameworkUtils。因为要考虑,rpc、mq、job,它其实不是 web;
|
||||
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
|
||||
if (loginUser == null) {
|
||||
return;
|
||||
}
|
||||
reqDTO.setUserId(loginUser.getId());
|
||||
reqDTO.setUserType(loginUser.getUserType());
|
||||
}
|
||||
|
||||
public static void fillModuleFields(OperateLogCreateReqDTO reqDTO, LogRecord logRecord) {
|
||||
reqDTO.setType(logRecord.getType()); // 大模块类型,例如:CRM 客户
|
||||
reqDTO.setSubType(logRecord.getSubType());// 操作名称,例如:转移客户
|
||||
reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 业务编号,例如:客户编号
|
||||
reqDTO.setAction(logRecord.getAction());// 操作内容,例如:修改编号为 1 的用户信息,将性别从男改成女,将姓名从ZT改成源码。
|
||||
reqDTO.setExtra(logRecord.getExtra()); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"}
|
||||
}
|
||||
|
||||
private static void fillRequestFields(OperateLogCreateReqDTO reqDTO) {
|
||||
// 获得 Request 对象
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
if (request == null) {
|
||||
return;
|
||||
}
|
||||
// 补全请求信息
|
||||
reqDTO.setRequestMethod(request.getMethod());
|
||||
reqDTO.setRequestUrl(request.getRequestURI());
|
||||
reqDTO.setUserIp(ServletUtils.getClientIP(request));
|
||||
reqDTO.setUserAgent(ServletUtils.getUserAgent(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogRecord> queryLog(String bizNo, String type) {
|
||||
throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
|
||||
throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 基于 mzt-log 框架
|
||||
* 实现操作日志功能
|
||||
*
|
||||
* @author HUIHUI
|
||||
*/
|
||||
package com.zt.plat.framework.operatelog;
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.framework.security.config;
|
||||
|
||||
import com.zt.plat.framework.web.config.WebProperties;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||
|
||||
/**
|
||||
* 自定义的 URL 的安全配置
|
||||
* 目的:每个 Maven Module 可以自定义规则!
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
public abstract class AuthorizeRequestsCustomizer
|
||||
implements Customizer<AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry>, Ordered {
|
||||
|
||||
@Resource
|
||||
private WebProperties webProperties;
|
||||
|
||||
protected String buildAdminApi(String url) {
|
||||
return webProperties.getAdminApi().getPrefix() + url;
|
||||
}
|
||||
|
||||
protected String buildAppApi(String url) {
|
||||
return webProperties.getAppApi().getPrefix() + url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.zt.plat.framework.security.config;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.permission.PermissionCommonApi;
|
||||
import com.zt.plat.framework.security.core.context.TransmittableThreadLocalSecurityContextHolderStrategy;
|
||||
import com.zt.plat.framework.security.core.filter.TokenAuthenticationFilter;
|
||||
import com.zt.plat.framework.security.core.handler.AccessDeniedHandlerImpl;
|
||||
import com.zt.plat.framework.security.core.handler.AuthenticationEntryPointImpl;
|
||||
import com.zt.plat.framework.security.core.service.SecurityFrameworkService;
|
||||
import com.zt.plat.framework.security.core.service.SecurityFrameworkServiceImpl;
|
||||
import com.zt.plat.framework.web.core.handler.GlobalExceptionHandler;
|
||||
import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
|
||||
/**
|
||||
* Spring Security 自动配置类,主要用于相关组件的配置
|
||||
*
|
||||
* 注意,不能和 {@link CloudWebSecurityConfigurerAdapter} 用一个,原因是会导致初始化报错。
|
||||
* 参见 https://stackoverflow.com/questions/53847050/spring-boot-delegatebuilder-cannot-be-null-on-autowiring-authenticationmanager 文档。
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@AutoConfigureOrder(-1) // 目的:先于 Spring Security 自动配置,避免一键改包后,org.* 基础包无法生效
|
||||
@EnableConfigurationProperties(SecurityProperties.class)
|
||||
public class CloudSecurityAutoConfiguration {
|
||||
|
||||
@Resource
|
||||
private SecurityProperties securityProperties;
|
||||
|
||||
/**
|
||||
* 认证失败处理类 Bean
|
||||
*/
|
||||
@Bean
|
||||
public AuthenticationEntryPoint authenticationEntryPoint() {
|
||||
return new AuthenticationEntryPointImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限不够处理器 Bean
|
||||
*/
|
||||
@Bean
|
||||
public AccessDeniedHandler accessDeniedHandler() {
|
||||
return new AccessDeniedHandlerImpl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Security 加密器
|
||||
* 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器
|
||||
*
|
||||
* @see <a href="http://stackabuse.com/password-encoding-with-spring-security/">Password Encoding with Spring Security</a>
|
||||
*/
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder(securityProperties.getPasswordEncoderLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Token 认证过滤器 Bean
|
||||
*/
|
||||
@Bean
|
||||
public TokenAuthenticationFilter authenticationTokenFilter(GlobalExceptionHandler globalExceptionHandler,
|
||||
OAuth2TokenCommonApi oauth2TokenApi) {
|
||||
return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler, oauth2TokenApi);
|
||||
}
|
||||
|
||||
@Bean("ss") // 使用 Spring Security 的缩写,方便使用
|
||||
public SecurityFrameworkService securityFrameworkService(PermissionCommonApi permissionApi) {
|
||||
return new SecurityFrameworkServiceImpl(permissionApi);
|
||||
}
|
||||
|
||||
/**
|
||||
* 声明调用 {@link SecurityContextHolder#setStrategyName(String)} 方法,
|
||||
* 设置使用 {@link TransmittableThreadLocalSecurityContextHolderStrategy} 作为 Security 的上下文策略
|
||||
*/
|
||||
@Bean
|
||||
public MethodInvokingFactoryBean securityContextHolderMethodInvokingFactoryBean() {
|
||||
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
|
||||
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
|
||||
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
|
||||
methodInvokingFactoryBean.setArguments(TransmittableThreadLocalSecurityContextHolderStrategy.class.getName());
|
||||
return methodInvokingFactoryBean;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.framework.security.config;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.permission.PermissionCommonApi;
|
||||
import com.zt.plat.framework.security.core.rpc.LoginUserRequestInterceptor;
|
||||
import com.zt.plat.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Security 使用到 Feign 的配置项
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableFeignClients(clients = {OAuth2TokenCommonApi.class, // 主要是引入相关的 API 服务
|
||||
PermissionCommonApi.class})
|
||||
public class CloudSecurityRpcAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public LoginUserRequestInterceptor loginUserRequestInterceptor() {
|
||||
return new LoginUserRequestInterceptor();
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.framework.security.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ConfigurationProperties(prefix = "cloud.security")
|
||||
@Validated
|
||||
@Data
|
||||
public class SecurityProperties {
|
||||
|
||||
/**
|
||||
* HTTP 请求时,访问令牌的请求 Header
|
||||
*/
|
||||
@NotEmpty(message = "Token Header 不能为空")
|
||||
private String tokenHeader = "Authorization";
|
||||
/**
|
||||
* HTTP 请求时,访问令牌的请求参数
|
||||
*
|
||||
* 初始目的:解决 WebSocket 无法通过 header 传参,只能通过 token 参数拼接
|
||||
*/
|
||||
@NotEmpty(message = "Token Parameter 不能为空")
|
||||
private String tokenParameter = "token";
|
||||
|
||||
/**
|
||||
* mock 模式的开关
|
||||
*/
|
||||
@NotNull(message = "mock 模式的开关不能为空")
|
||||
private Boolean mockEnable = false;
|
||||
/**
|
||||
* mock 模式的密钥
|
||||
* 一定要配置密钥,保证安全性
|
||||
*/
|
||||
@NotEmpty(message = "mock 模式的密钥不能为空") // 这里设置了一个默认值,因为实际上只有 mockEnable 为 true 时才需要配置。
|
||||
private String mockSecret = "test";
|
||||
|
||||
/**
|
||||
* 免登录的 URL 列表
|
||||
*/
|
||||
private List<String> permitAllUrls = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* PasswordEncoder 加密复杂度,越高开销越大
|
||||
*/
|
||||
private Integer passwordEncoderLength = 4;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user