mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-28 01:53:53 +08:00
Merge pull request #3294 from xinnan-tech/fix/manager-api-startup-warnings
fix(manager-api): 消除启动阶段告警
This commit is contained in:
@@ -12,6 +12,11 @@ import xiaozhi.modules.device.entity.DeviceAddressBookEntity;
|
|||||||
@Mapper
|
@Mapper
|
||||||
public interface DeviceAddressBookDao extends BaseMapper<DeviceAddressBookEntity> {
|
public interface DeviceAddressBookDao extends BaseMapper<DeviceAddressBookEntity> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增设备通讯录记录
|
||||||
|
*/
|
||||||
|
int insertAddressBook(DeviceAddressBookEntity entity);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取设备通讯录列表
|
* 获取设备通讯录列表
|
||||||
*/
|
*/
|
||||||
@@ -31,4 +36,4 @@ public interface DeviceAddressBookDao extends BaseMapper<DeviceAddressBookEntity
|
|||||||
* 批量删除设备相关的通讯录记录
|
* 批量删除设备相关的通讯录记录
|
||||||
*/
|
*/
|
||||||
void deleteByMacAddresses(@Param("macAddresses") List<String> macAddresses);
|
void deleteByMacAddresses(@Param("macAddresses") List<String> macAddresses);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -167,7 +167,7 @@ public class DeviceAddressBookServiceImpl implements DeviceAddressBookService {
|
|||||||
alias = generateUniqueAlias(macAddress, targetMac, alias);
|
alias = generateUniqueAlias(macAddress, targetMac, alias);
|
||||||
entity.setAlias(alias);
|
entity.setAlias(alias);
|
||||||
entity.setHasPermission(hasPermission);
|
entity.setHasPermission(hasPermission);
|
||||||
deviceAddressBookDao.insert(entity);
|
deviceAddressBookDao.insertAddressBook(entity);
|
||||||
} else {
|
} else {
|
||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
updateAlias(macAddress, targetMac, alias);
|
updateAlias(macAddress, targetMac, alias);
|
||||||
|
|||||||
@@ -4,16 +4,19 @@ import java.util.HashMap;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.shiro.mgt.SecurityManager;
|
|
||||||
import org.apache.shiro.session.mgt.SessionManager;
|
import org.apache.shiro.session.mgt.SessionManager;
|
||||||
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
|
||||||
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
|
||||||
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
import org.apache.shiro.web.config.ShiroFilterConfiguration;
|
import org.apache.shiro.web.config.ShiroFilterConfiguration;
|
||||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||||
|
import org.apache.shiro.web.mgt.WebSecurityManager;
|
||||||
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
|
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
|
||||||
import jakarta.servlet.Filter;
|
import jakarta.servlet.Filter;
|
||||||
import xiaozhi.modules.security.oauth2.Oauth2Filter;
|
import xiaozhi.modules.security.oauth2.Oauth2Filter;
|
||||||
@@ -39,7 +42,7 @@ public class ShiroConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean("securityManager")
|
@Bean("securityManager")
|
||||||
public SecurityManager securityManager(Oauth2Realm oAuth2Realm, SessionManager sessionManager) {
|
public WebSecurityManager securityManager(Oauth2Realm oAuth2Realm, SessionManager sessionManager) {
|
||||||
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
||||||
securityManager.setRealm(oAuth2Realm);
|
securityManager.setRealm(oAuth2Realm);
|
||||||
securityManager.setSessionManager(sessionManager);
|
securityManager.setSessionManager(sessionManager);
|
||||||
@@ -48,7 +51,8 @@ public class ShiroConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean("shiroFilter")
|
@Bean("shiroFilter")
|
||||||
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager, SysParamsService sysParamsService) {
|
public static ShiroFilterFactoryBean shirFilter(@Lazy WebSecurityManager securityManager,
|
||||||
|
@Lazy SysParamsService sysParamsService) {
|
||||||
ShiroFilterConfiguration config = new ShiroFilterConfiguration();
|
ShiroFilterConfiguration config = new ShiroFilterConfiguration();
|
||||||
config.setFilterOncePerRequest(true);
|
config.setFilterOncePerRequest(true);
|
||||||
|
|
||||||
@@ -101,12 +105,14 @@ public class ShiroConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean("lifecycleBeanPostProcessor")
|
@Bean("lifecycleBeanPostProcessor")
|
||||||
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
|
||||||
return new LifecycleBeanPostProcessor();
|
return new LifecycleBeanPostProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||||
|
public static AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
|
||||||
|
@Lazy WebSecurityManager securityManager) {
|
||||||
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
|
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
|
||||||
advisor.setSecurityManager(securityManager);
|
advisor.setSecurityManager(securityManager);
|
||||||
return advisor;
|
return advisor;
|
||||||
|
|||||||
@@ -1,20 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<!-- 启用JansiConsoleAppender以确保控制台输出有颜色 -->
|
|
||||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
|
|
||||||
|
|
||||||
<!-- 确保日志目录存在 -->
|
|
||||||
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
|
|
||||||
|
|
||||||
<!-- 定义日志文件存储位置 -->
|
<!-- 定义日志文件存储位置 -->
|
||||||
<property name="LOG_HOME" value="./logs" />
|
<property name="LOG_HOME" value="./logs" />
|
||||||
|
|
||||||
<!-- 使用自定义的初始化监听器确保日志目录存在 -->
|
|
||||||
<define name="LOGBACK_DIR_CHECK" class="ch.qos.logback.core.property.FileExistsPropertyDefiner">
|
|
||||||
<path>${LOG_HOME}</path>
|
|
||||||
<createIfMissing>true</createIfMissing>
|
|
||||||
</define>
|
|
||||||
|
|
||||||
<!-- 引入Spring Boot默认配置 -->
|
<!-- 引入Spring Boot默认配置 -->
|
||||||
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
WHERE mac_address = #{macAddress} AND target_mac = #{targetMac}
|
WHERE mac_address = #{macAddress} AND target_mac = #{targetMac}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<insert id="insert">
|
<insert id="insertAddressBook">
|
||||||
INSERT INTO ai_device_address_book (mac_address, target_mac, alias, has_permission, creator, create_date, updater, update_date)
|
INSERT INTO ai_device_address_book (mac_address, target_mac, alias, has_permission, creator, create_date, updater, update_date)
|
||||||
VALUES (#{macAddress}, #{targetMac}, #{alias}, #{hasPermission}, #{creator}, NOW(), #{updater}, NOW())
|
VALUES (#{macAddress}, #{targetMac}, #{alias}, #{hasPermission}, #{creator}, NOW(), #{updater}, NOW())
|
||||||
</insert>
|
</insert>
|
||||||
@@ -36,4 +36,4 @@
|
|||||||
#{mac}
|
#{mac}
|
||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package xiaozhi.modules.device.service.impl;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import xiaozhi.common.redis.RedisUtils;
|
||||||
|
import xiaozhi.modules.device.dao.DeviceAddressBookDao;
|
||||||
|
import xiaozhi.modules.device.entity.DeviceAddressBookEntity;
|
||||||
|
import xiaozhi.modules.device.service.DeviceService;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
|
|
||||||
|
class DeviceAddressBookServiceImplTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void newEntryUsesTheDedicatedAddressBookInsertMapping() {
|
||||||
|
DeviceAddressBookDao addressBookDao = mock(DeviceAddressBookDao.class);
|
||||||
|
RedisUtils redisUtils = mock(RedisUtils.class);
|
||||||
|
DeviceService deviceService = mock(DeviceService.class);
|
||||||
|
SysParamsService sysParamsService = mock(SysParamsService.class);
|
||||||
|
DeviceAddressBookServiceImpl service = new DeviceAddressBookServiceImpl(
|
||||||
|
addressBookDao, redisUtils, deviceService, sysParamsService);
|
||||||
|
when(addressBookDao.selectOne(any())).thenReturn(null);
|
||||||
|
when(addressBookDao.selectList(null)).thenReturn(List.of());
|
||||||
|
|
||||||
|
service.saveOrUpdate("00:11:22:33:44:55", "00:11:22:33:44:66", "living-room", true);
|
||||||
|
|
||||||
|
ArgumentCaptor<DeviceAddressBookEntity> entityCaptor = ArgumentCaptor.forClass(DeviceAddressBookEntity.class);
|
||||||
|
verify(addressBookDao).insertAddressBook(entityCaptor.capture());
|
||||||
|
DeviceAddressBookEntity entity = entityCaptor.getValue();
|
||||||
|
assertEquals("00:11:22:33:44:55", entity.getMacAddress());
|
||||||
|
assertEquals("00:11:22:33:44:66", entity.getTargetMac());
|
||||||
|
assertEquals("living-room", entity.getAlias());
|
||||||
|
assertTrue(entity.getHasPermission());
|
||||||
|
verify(addressBookDao, never()).insert(any(DeviceAddressBookEntity.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package xiaozhi.modules.security.config;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
|
import org.apache.shiro.session.mgt.SessionManager;
|
||||||
|
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
|
||||||
|
import org.apache.shiro.web.mgt.WebSecurityManager;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.annotation.Role;
|
||||||
|
|
||||||
|
import xiaozhi.modules.security.oauth2.Oauth2Realm;
|
||||||
|
import xiaozhi.modules.sys.service.SysParamsService;
|
||||||
|
|
||||||
|
class ShiroConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void beanPostProcessorFactoriesDoNotInstantiateShiroConfigOrBusinessDependenciesEarly() throws Exception {
|
||||||
|
Method lifecycleFactory = ShiroConfig.class.getDeclaredMethod("lifecycleBeanPostProcessor");
|
||||||
|
Method filterFactory = ShiroConfig.class.getDeclaredMethod(
|
||||||
|
"shirFilter", WebSecurityManager.class, SysParamsService.class);
|
||||||
|
|
||||||
|
assertTrue(Modifier.isStatic(lifecycleFactory.getModifiers()));
|
||||||
|
assertTrue(BeanPostProcessor.class.isAssignableFrom(ShiroFilterFactoryBean.class));
|
||||||
|
assertTrue(Modifier.isStatic(filterFactory.getModifiers()));
|
||||||
|
Lazy securityManagerLazy = filterFactory.getParameters()[0].getAnnotation(Lazy.class);
|
||||||
|
Lazy sysParamsServiceLazy = filterFactory.getParameters()[1].getAnnotation(Lazy.class);
|
||||||
|
assertNotNull(securityManagerLazy);
|
||||||
|
assertNotNull(sysParamsServiceLazy);
|
||||||
|
assertTrue(securityManagerLazy.value());
|
||||||
|
assertTrue(sysParamsServiceLazy.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void authorizationAdvisorIsInfrastructureAndDefersItsSecurityManager() throws Exception {
|
||||||
|
Method advisorFactory = ShiroConfig.class.getDeclaredMethod(
|
||||||
|
"authorizationAttributeSourceAdvisor", WebSecurityManager.class);
|
||||||
|
|
||||||
|
assertTrue(Modifier.isStatic(advisorFactory.getModifiers()));
|
||||||
|
Lazy securityManagerLazy = advisorFactory.getParameters()[0].getAnnotation(Lazy.class);
|
||||||
|
assertNotNull(securityManagerLazy);
|
||||||
|
assertTrue(securityManagerLazy.value());
|
||||||
|
assertEquals(BeanDefinition.ROLE_INFRASTRUCTURE, advisorFactory.getAnnotation(Role.class).value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void securityManagerRetainsTheWebSecurityContractRequiredByShiroFilter() throws Exception {
|
||||||
|
Method securityManagerFactory = ShiroConfig.class.getDeclaredMethod(
|
||||||
|
"securityManager", Oauth2Realm.class, SessionManager.class);
|
||||||
|
|
||||||
|
assertEquals(WebSecurityManager.class, securityManagerFactory.getReturnType());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user