refactor(security): 修正静态资源配置

This commit is contained in:
2025-12-31 15:18:18 +08:00
parent cddb0cff08
commit bab3ea1a15
15 changed files with 192 additions and 362 deletions
@@ -0,0 +1,35 @@
package cn.odboy.system.controller;
import cn.odboy.base.KitPageArgs;
import cn.odboy.base.KitPageResult;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.model.SystemQueryOperationLogArgs;
import cn.odboy.system.service.SystemOperationLogService;
import cn.odboy.util.KitPageUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统:审计日志")
@RequestMapping("/api/logs")
public class SystemOperationLogController {
@Autowired
private SystemOperationLogService systemOperationLogService;
@PostMapping(value = "/searchUserLog")
@ApiOperation("用户日志查询")
public ResponseEntity<KitPageResult<SystemOperationLogTb>> searchUserLog(@Validated @RequestBody KitPageArgs<SystemQueryOperationLogArgs> pageArgs) {
IPage<SystemOperationLogTb> systemOperationLogTbPage = systemOperationLogService.searchUserLog(pageArgs);
return new ResponseEntity<>(KitPageUtil.toPage(systemOperationLogTbPage), HttpStatus.OK);
}
}
@@ -0,0 +1,11 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SystemQueryOperationLogArgs extends KitObject {
}
@@ -1,39 +0,0 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 捕捉操作日志
*
* @author odboy
* @date 2025-05-12
*/
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
String bizName() default "";
}
@@ -1,120 +0,0 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.mysql.SystemOperationLogMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBrowserUtil;
import cn.odboy.util.KitIPUtil;
import com.alibaba.fastjson2.JSON;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 捕捉操作日志
*
* @author odboy
* @date 2025-05-12
*/
@Slf4j
@Aspect
@Component
public class OperationLogAspect {
@Autowired
private SystemOperationLogMapper systemOperationLogMapper;
@Around("@annotation(operationLog)")
public Object operationLogCatch(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
return handleLog(joinPoint, operationLog);
}
private Object handleLog(ProceedingJoinPoint joinPoint, OperationLog annotation) throws Throwable {
TimeInterval timeInterval = new TimeInterval();
try {
Object result = joinPoint.proceed();
SystemOperationLogTb record = getOperationLogTb(joinPoint, annotation, timeInterval);
Thread.startVirtualThread(() -> {
try {
systemOperationLogMapper.insert(record);
} catch (Exception e) {
// 忽略
}
});
return result;
} catch (Throwable exception) {
SystemOperationLogTb record = getOperationLogTb(joinPoint, annotation, timeInterval);
record.setExceptionDetail(ExceptionUtil.stacktraceToString(exception));
Thread.startVirtualThread(() -> {
try {
systemOperationLogMapper.insert(record);
} catch (Exception e) {
// 忽略
}
});
throw exception;
}
}
private SystemOperationLogTb getOperationLogTb(ProceedingJoinPoint joinPoint, OperationLog annotation,
TimeInterval timeInterval) {
long executeTime = timeInterval.intervalMs();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String bizName = annotation.bizName();
if (StrUtil.isBlank(bizName)) {
Method method = signature.getMethod();
Operation apiOperation = method.getAnnotation(Operation.class);
if (apiOperation != null) {
bizName = apiOperation.summary();
}
}
if (StrUtil.isBlank(bizName)) {
bizName = "默认业务";
}
String method = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
Object[] args = joinPoint.getArgs();
String params = JSON.toJSONString(args);
HttpServletRequest request = KitRequestHolder.getHttpServletRequest();
String requestIp = KitBrowserUtil.getIp(request);
String browserInfo = KitBrowserUtil.getVersion(request);
String address = KitIPUtil.getCityInfo(requestIp);
String username = KitSecurityHelper.getCurrentUsername();
SystemOperationLogTb record = new SystemOperationLogTb();
record.setBizName(bizName);
record.setMethod(method);
record.setParams(params);
record.setRequestIp(requestIp);
record.setExecuteTime(executeTime);
record.setUsername(username);
record.setAddress(address);
record.setBrowserInfo(browserInfo);
return record;
}
}
@@ -1,38 +0,0 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog.annotaions;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 捕捉操作日志
*
* @author odboy
* @date 2025-05-12
*/
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
String bizName() default "";
}
@@ -1,122 +0,0 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog.core;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.mysql.SystemOperationLogMapper;
import cn.odboy.system.framework.operalog.annotaions.OperationLog;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBrowserUtil;
import cn.odboy.util.KitIPUtil;
import com.alibaba.fastjson2.JSON;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 捕捉操作日志
*
* @author odboy
* @date 2025-05-12
*/
@Slf4j
@Aspect
@Component
public class SystemOperationLogAspect {
@Autowired
private SystemOperationLogMapper systemOperationLogMapper;
@Around("@annotation(operationLog)")
public Object operationLogCatch(ProceedingJoinPoint joinPoint, OperationLog operationLog) throws Throwable {
return handleLog(joinPoint, operationLog);
}
private Object handleLog(ProceedingJoinPoint joinPoint, OperationLog annotation) throws Throwable {
TimeInterval timeInterval = new TimeInterval();
try {
Object result = joinPoint.proceed();
SystemOperationLogTb record = getOperationLogTb(joinPoint, annotation, timeInterval);
Thread.startVirtualThread(() -> {
try {
systemOperationLogMapper.insert(record);
} catch (Exception e) {
// log.error("保存审计日志失败", e);
// 忽略
}
});
return result;
} catch (Throwable exception) {
SystemOperationLogTb record = getOperationLogTb(joinPoint, annotation, timeInterval);
record.setExceptionDetail(ExceptionUtil.stacktraceToString(exception));
Thread.startVirtualThread(() -> {
try {
systemOperationLogMapper.insert(record);
} catch (Exception e) {
// log.error("保存审计日志失败", e);
// 忽略
}
});
throw exception;
}
}
private SystemOperationLogTb getOperationLogTb(ProceedingJoinPoint joinPoint, OperationLog annotation,
TimeInterval timeInterval) {
long executeTime = timeInterval.intervalMs();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String bizName = annotation.bizName();
if (StrUtil.isBlank(bizName)) {
Method method = signature.getMethod();
Operation apiOperation = method.getAnnotation(Operation.class);
if (apiOperation != null) {
bizName = apiOperation.summary();
}
}
if (StrUtil.isBlank(bizName)) {
bizName = "默认业务";
}
String method = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
Object[] args = joinPoint.getArgs();
String params = JSON.toJSONString(args);
HttpServletRequest request = KitRequestHolder.getHttpServletRequest();
String requestIp = KitBrowserUtil.getIp(request);
String browserInfo = KitBrowserUtil.getVersion(request);
String address = KitIPUtil.getCityInfo(requestIp);
String username = KitSecurityHelper.getCurrentUsername();
SystemOperationLogTb record = new SystemOperationLogTb();
record.setBizName(bizName);
record.setMethod(method);
record.setParams(params);
record.setRequestIp(requestIp);
record.setExecuteTime(executeTime);
record.setUsername(username);
record.setAddress(address);
record.setBrowserInfo(browserInfo);
return record;
}
}
@@ -93,8 +93,8 @@ public class SpringSecurityConfig {
.sessionManagement(
sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorizeRequests -> authorizeRequests
// 静态资源等等
.requestMatchers(HttpMethod.GET, "*.html", "*.css", "*.js", "/websocket/**").permitAll()
// 静态资源等
.requestMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/websocket/**").permitAll()
// Knife4j 和 OpenAPI 相关路径
.requestMatchers("/doc.html", "/webjars/**", "/v3/api-docs", "/v3/api-docs/**", "/swagger-resources",
"/swagger-resources/**", "/configuration/ui", "/configuration/security").permitAll()
@@ -0,0 +1,42 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.openapi;
import cn.odboy.annotation.AnonymousPostMapping;
import cn.odboy.system.service.SystemAuthService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/captcha")
@Api(tags = "系统:验证码管理")
public class SystemCaptchaOpenController {
@Autowired
private SystemAuthService systemAuthService;
@ApiOperation("获取验证码")
@AnonymousPostMapping(value = "/getCode")
public ResponseEntity<Map<String, Object>> getCode() {
Map<String, Object> imgResult = systemAuthService.getCaptchaInfo();
return ResponseEntity.ok(imgResult);
}
}
@@ -0,0 +1,26 @@
package cn.odboy.system.service;
import cn.odboy.base.KitPageArgs;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.model.SystemQueryOperationLogArgs;
import cn.odboy.system.dal.mysql.SystemOperationLogMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SystemOperationLogService {
@Autowired
private SystemOperationLogMapper systemOperationLogMapper;
public IPage<SystemOperationLogTb> searchUserLog(KitPageArgs<SystemQueryOperationLogArgs> pageArgs) {
LambdaQueryWrapper<SystemOperationLogTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemOperationLogTb::getUsername, KitSecurityHelper.getCurrentUsername());
Page<SystemOperationLogTb> page = new Page<>(pageArgs.getPage(), pageArgs.getSize());
return systemOperationLogMapper.selectPage(page, wrapper);
}
}
@@ -0,0 +1,37 @@
package cn.odboy.system.controller;
import cn.odboy.base.KitPageArgs;
import cn.odboy.base.KitPageResult;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.model.SystemQueryDeptArgs;
import cn.odboy.system.dal.model.SystemQueryOperationLogArgs;
import cn.odboy.system.service.SystemOperationLogService;
import cn.odboy.util.KitPageUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(tags = "系统:审计日志")
@RequestMapping("/api/logs")
public class SystemOperationLogController {
@Autowired
private SystemOperationLogService systemOperationLogService;
@PostMapping(value = "/searchUserLog")
@ApiOperation("用户日志查询")
public ResponseEntity<KitPageResult<SystemOperationLogTb>> searchUserLog(@Validated @RequestBody KitPageArgs<SystemQueryOperationLogArgs> pageArgs) {
IPage<SystemOperationLogTb> systemOperationLogTbPage = systemOperationLogService.searchUserLog(pageArgs);
return new ResponseEntity<>(KitPageUtil.toPage(systemOperationLogTbPage), HttpStatus.OK);
}
}
@@ -0,0 +1,11 @@
package cn.odboy.system.dal.model;
import cn.odboy.base.KitObject;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class SystemQueryOperationLogArgs extends KitObject {
}
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog.core;
package cn.odboy.system.framework.operalog;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.exceptions.ExceptionUtil;
@@ -22,7 +22,6 @@ import cn.hutool.core.util.StrUtil;
import cn.odboy.framework.context.KitRequestHolder;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.mysql.SystemOperationLogMapper;
import cn.odboy.system.framework.operalog.annotaions.OperationLog;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import cn.odboy.util.KitBrowserUtil;
import cn.odboy.util.KitIPUtil;
@@ -1,38 +0,0 @@
/*
* Copyright 2021-2025 Odboy
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.odboy.system.framework.operalog.annotaions;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 捕捉操作日志
*
* @author odboy
* @date 2025-05-12
*/
@Inherited
@Documented
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
String bizName() default "";
}
@@ -80,7 +80,7 @@ public class SpringSecurityConfig {
.and().headers().frameOptions().disable()
// 不创建会话
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
// 静态资源等等
// 静态资源等
.antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/websocket/**").permitAll()
// swagger 文档
.antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources/**").permitAll()
@@ -0,0 +1,26 @@
package cn.odboy.system.service;
import cn.odboy.base.KitPageArgs;
import cn.odboy.system.dal.dataobject.SystemOperationLogTb;
import cn.odboy.system.dal.model.SystemQueryOperationLogArgs;
import cn.odboy.system.dal.mysql.SystemOperationLogMapper;
import cn.odboy.system.framework.permission.core.KitSecurityHelper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class SystemOperationLogService {
@Autowired
private SystemOperationLogMapper systemOperationLogMapper;
public IPage<SystemOperationLogTb> searchUserLog(KitPageArgs<SystemQueryOperationLogArgs> pageArgs) {
LambdaQueryWrapper<SystemOperationLogTb> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SystemOperationLogTb::getUsername, KitSecurityHelper.getCurrentUsername());
Page<SystemOperationLogTb> page = new Page<>(pageArgs.getPage(), pageArgs.getSize());
return systemOperationLogMapper.selectPage(page, wrapper);
}
}