springboot中endpoint的安全访问,需要谨慎设计,endpoint可以暴露很多有用的信息,这对外部数据采集器来说非常便捷,但是潜在也引入了安全问题,稍有不慎可能被非法访问。本文基于springboot2,基于spring-security来认证endpoint的访问授权。
在springboot2之后,health和info接口将是公开的,其他endpoint将默认在security的控制之下,不允许被访问,如果需要访问,则必须接入security。本文描述,如果将health和info接口继续保持公开(当然也可以安全控制)、其他endpoint需要授权才能访问,此外web项目的其他接口则可以正常访问。
1)将spring-security(或者其starter)加入classpath。
2)基于security实现httpBasic授权认证,保护其他endpoint。
springboot2默认实现,有些不妥之处,一旦引入security,不仅endpoint被防护,web项目的其他接口也被拦截,这一点需要重新设计。我们通过实现自定义的security配置,并覆盖原有安全配置。
一、pom.xml
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
二、Environment设置
import org.apache.commons.lang3.RandomStringUtils; import org.springframework.boot.SpringApplication; import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; import java.util.Map; import java.util.TreeMap; /** * @author liuguanqing * created 2018/11/2 3:32 PM * 调整优化环境变量,对于框架会默认覆盖一些环境变量,此时我们需要在processor中执行 * 我们不再需要使用单独的yml文件来解决此问题。原则: * 1)所有设置为系统属性的,初衷为"对系统管理员可见"、"对外部接入组件可见"(比如starter或者日志组件等) * 2)对设置为lastSource,表示"当用户没有通过yml"配置选项时的默认值--担保策略。 **/ public class MeteorEnvironmentPostProcessor implements EnvironmentPostProcessor { //可以被application覆盖的配置,此处作为默认担保 private static final Map<String, Object> lastSource = new TreeMap<>(); //框架限定,不能被覆盖或者外部指定无效的配置 private static final Map<String,Object> firstSource = new TreeMap<>(); private static final String NAME_FIRST = "CUSTOMIZE_FIRST"; private static final String NAME_LAST = "CUSTOMIZE_LAST"; @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { MutablePropertySources propertySources = environment.getPropertySources(); //已装载,则中断 if (propertySources.contains(NAME_FIRST) || propertySources.contains(NAME_LAST)) { return; } resolveSecurity(environment); resolveManagement(environment); MapPropertySource lastPropertySource = new MapPropertySource(CONTEXT_NAME_LAST, lastSource); propertySources.addLast(lastPropertySource); MapPropertySource firstPropertySource = new MapPropertySource(CONTEXT_NAME_FIRST, firstSource); propertySources.addFirst(firstPropertySource); } private void resolveSecurity(final ConfigurableEnvironment environment) { String password = environment.getProperty(PASSWORD); if (password == null) { password = environment.getProperty("spring.security.user.password"); } if (password == null) { password = RandomStringUtils.random(16,true,true); } firstSource.put("spring.security.user.password",password); //可被系统管理员查看 System.setProperty(WEB_SECURITY_PASSWORD_SP_KEY,password); //覆盖 firstSource.put("spring.security.user.name","application"); lastSource.put("spring.security.user.roles","application"); } private void resolveManagement(final ConfigurableEnvironment environment) { //有关Endpoints安全问题 String excludes = environment.getProperty("spring.autoconfigure.exclude"); StringBuilder sb = new StringBuilder(); if(excludes != null) { sb.append(","); } //关闭spring-boot默认的security配置 sb.append(ManagementWebSecurityAutoConfiguration.class.getName()); firstSource.put("spring.autoconfigure.exclude",sb.toString()); //默认全部关闭 firstSource.put("management.endpoints.enabled-by-default",false); firstSource.put("management.endpoints.jmx.domain",ContextConstants.JMX_DOMAIN); firstSource.put("management.endpoints.jmx.exposure.include","*"); firstSource.put("management.endpoints.web.exposure.include","*"); firstSource.put("management.endpoints.web.exposure.exclude","shutdown,threaddump,heapdump"); firstSource.put("management.endpoints.web.base-path","/actuator"); firstSource.put("management.endpoint.health.enabled",true); lastSource.put("management.endpoint.health.show-details","never"); firstSource.put("management.endpoint.info.enabled",true); firstSource.put("management.endpoint.mappings.enabled",true); firstSource.put("management.endpoint.metrics.enabled",true); firstSource.put("management.endpoint.env.enabled",true); firstSource.put("management.endpoint.configprops.enabled",true); firstSource.put("management.endpoint.beans.enabled",true); firstSource.put("management.endpoint.httptrace.enabled",true); } }
有时候,我们不希望用户干扰有关security和endpoint的参数配置,比如用户好奇的打开或者关闭了一些“不安全的”endpoint,将可能导致一些严重的事故,我们需要在项目框架中集成有关Environment的处理器,强制覆盖有关配置。
比如本文,有关endpoint的开关配置是用户无法配置的(不生效),我们也强制为项目设定security的用户名和密码。
需要注意,这个EnvironmentPostProcessor会被执行两次,分别为spring环境和servlet环境,此时Environment类型不同,所以如果你在Porcessor中处理有关“字符串拼接”、“累加”等操作时需要慎重。
三、自定义Security配置
/** * created 2018/11/5 2:34 PM * 用于保护endpoint不被非法访问 **/ @Order(99) public class MeteorWebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { //普通web资源 } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .requestMatchers( EndpointRequest.to(MetricsEndpoint.class, EnvironmentEndpoint.class, HttpTraceEndpoint.class, ConfigurationPropertiesReportEndpoint.class, BeansEndpoint.class, MappingsEndpoint.class)).hasRole("application").anyRequest() .permitAll().and() .httpBasic(); } }
安全控制策略需要特别注意,如果上下文中有多个WebSecurityConfigurerAdapter,必须为每个实现声明@Order和指定顺序且order不能重复,此外@Order只能声明在类上,不能声明在@Bean。
对于springboot2而言,默认已经提供了一个有关endpoint的安全控制类:ManagementWebSecurityAutoConfiguration,这个类的加载条件也“如果上下文中没有提供“WebSecurityConfigurerAdapter”实现,ManagementWebSecurityAutoConfiguration主要是为了将“health和info”可被公开访问、其他接口需要认证授权,为了避免不必要的设计问题,我们强制关闭此类的自动装配(或者开发自定义的WebSecurityConfigurerAdapter,且优先级高于100)。
1)通过@SpringBootApplication(exclude = {ManagementWebSecurityAutoConfiguration.class})。
2)在yml中显式声明:
spring.autoconfigure.exclude=org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
3)你可以像本文描述,通过上述EnvironmentPostProcessor,强制覆盖“spring.autofigure.exclude”的参数,并追加ManagementWebSecurityAutoConfiguration。
如果你的上下文中,有多个自定义的WebSecurityConfigurerAdapter实现,那么他们的Order必须唯一,否则将会抛出:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: @Order on WebSecurityConfigurers must be unique. Order of 100 was already used on com.example.demo.Application$TestSecurity@54c60202, so it cannot be used on org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityConfigurerAdapter$$EnhancerBySpringCGLIB$$1d8564e5@7889b4b9 too.
三、初始化WebSecurityConfigurerAdapter
@Bean public WebSecurityConfigurer meteorWebSecurityConfigurer() { return new MeteorWebSecurityConfigurer(); }
此代码,可以放在任何被@Configuration修饰的类中,当然也可以为你自定义的AutoConfiguration类中。
四、配置Environment处理器(META-INF/spring.factories)
org.springframework.boot.env.EnvironmentPostProcessor=\ com.test.springboot.environment.MeteorEnvironmentPostProcessor
五、yml配置
spring: security: user: name: application password: ${password:test123}
你可以通过启动时使用“-Dpassword=”来传入密码,这样必要安全,如果未传入,则使用“test123”。
六、访问与验证
此后,我们也已通过postman、浏览器、curl等方式验证安全是否生效:
> curl http://127.0.0.1:8080/actuator/metrics -u application:test123 或者 > curl http://application:test123@127.0.0.1:8080/actuator/metrics #可以访问 > curl http://127.0.0.1:8080/actuator/health ##无认证可以访问 > curl http://127.0.0.1:8080/index ##无认证可以访问 > curl http://127.0.0.1:8080/actuator/metrics ##401错误
相关推荐
在本文中,我们将深入探讨如何使用SpringBoot与OSS(Object Storage Service)集成,实现...在实际开发中,可以根据业务需求进行定制化改造,如增加权限控制、文件版本管理等功能,进一步提升系统的实用性和安全性。
@Controller注解表明该类是一个控制器,而@EnableAutoConfiguration注解则表明SpringBoot将根据添加的jar依赖来猜测如何配置Spring。 SpringBoot应用安全终止 SpringBoot应用安全终止是指在SpringBoot应用运行时...
- **Endpoint Security**:默认情况下,Actuator端点是开放的,但在生产环境中,为了安全考虑,通常需要进行权限控制,可以通过`management.security.enabled`属性来启用或禁用端点的安全性。 - **自定义Endpoint*...
在IT行业中,Spring Boot和Apache CXF是两个非常重要的组件,它们在开发高效、轻量级的Web服务中发挥着...在实际开发中,还可以根据需求进一步定制CXF的行为,例如添加安全控制、错误处理等,以满足更复杂的应用场景。
在实际项目中,你可能还需要考虑其他因素,如文件权限管理、文件版本控制、对象生命周期策略、监控与日志记录等。此外,还可以利用SpringBoot的缓存管理、事务支持等功能,进一步优化系统的性能和稳定性。对于安全...
以下是这个"springboot mysql jdbc示例"中的关键知识点: 1. **Spring Boot**: Spring Boot是Spring框架的一个扩展,它提供了快速开发新Spring应用的方式,通过预设默认配置,减少了常规的Spring应用所需的初始设置...
总之,"全套SpringBoot从零到有"的学习资源可能包括了Spring Boot的安装与配置、核心概念解析、实战案例、异常处理、安全控制、日志管理、单元测试等多个方面的内容。通过系统学习,你将能够熟练地运用Spring Boot来...
6. **Actuator**:SpringBoot Actuator提供了一组端点(Endpoint),用于监控和管理应用程序,包括健康检查、指标收集、日志查看等。这对于理解和优化理财系统的运行状态非常有帮助。 7. **Docker化部署**:...
在本文中,我们将深入探讨如何使用SpringBoot集成Apache CXF来开发Web服务。SpringBoot以其简洁的配置和快速的应用启动而受到广大开发者的欢迎,而CXF是一个强大的开源框架,用于构建和消费Web服务。结合这两者,...
3. **OSS服务配置**:在SpringBoot应用中,我们需要配置OSS的相关参数,包括访问密钥(AccessKey ID和AccessKey Secret)、Endpoint(OSS服务的访问域名)以及Bucket(存储空间)名称。这些通常在项目的配置文件(如...
3. **使用Spring Security扩展**: Spring Security提供了OAuth2的集成,可以轻松添加安全控制。 ## 自定义Endpoint SpringBoot允许你自定义Actuator的Endpoint,以便监控和管理应用的健康状况、指标和其他信息。这...
本文将详细介绍如何在SpringBoot项目中整合MinIO,帮助开发者实现高效、安全的文件存储功能。 **一、MinIO简介** MinIO是一款高性能、开源的对象存储系统,设计目标是提供简单、快速、安全的数据访问接口。它的...
在Spring Boot中,我们需要配置WebSocket的Endpoint。这通常通过实现`WebSocketHandler`接口或者扩展`TextWebSocketHandler`或`BinaryWebSocketHandler`来完成。此外,还需要在`WebMvcConfigurer`或`...
在 SpringBoot 官方文档的第 4 部分中介绍了为应用发布生产准备的各种特性,其中,通过 Actuator 的 HTTP Endpoint,开发人员可以方便地对应用的监控与管理。引入指定的 starter 包,并在 application.yml 中打开...
**SpringBoot集成MinIO快速入门** 在现代的Web开发中,数据存储是一个不可或缺的部分,而文件存储服务在很多场景下都是必要的。...记得在生产环境中,安全总是首要的,确保对敏感信息(如访问密钥)进行妥善管理。
在现代Web开发中,由于浏览器的安全策略,前后端分离的应用常常会遇到跨域问题。同源策略限制了JavaScript从一个源获取另一个源的数据,导致不同域名、端口或协议之间的通信受到阻碍。本文将深入探讨如何在...
- Spring Security为SpringBoot应用提供了安全控制,包括身份验证和授权。 - 可以通过`spring-boot-starter-security`启动器添加安全功能,配置基本的用户名/密码登录,或使用OAuth2、JWT等高级认证机制。 7. **...
- `management.endpoint.health.show-details`: 控制健康检查详情是否显示。 以上仅列举了部分常用配置项,实际上Spring Boot支持的配置参数远不止这些。通过合理配置这些参数,开发者可以轻松地调整Spring Boot...
2. 创建 REST 控制器:创建一个带有 `@RestController` 注解的 Java 类,它表示该类中的方法将返回 JSON 或其他响应格式的数据。例如: ```java import org.springframework.web.bind.annotation.GetMapping; ...
6. **安全控制** - **Spring Security**:Spring Boot 提供对安全的默认配置,可以轻松实现身份验证和授权,如使用 `@Secured` 或 `@PreAuthorize` 注解进行权限控制。 7. **测试** - **Spring Boot 测试支持**:...