• 20220517 Web


    前言

    文档地址

    Spring Boot非常适合于Web应用程序开发。您可以使用嵌入式 Tomcat,Jetty,Undertow 或 Netty 创建独立的 HTTP 服务器。大多数 Web 应用程序都使用 spring-boot-starter-web 模块来快速启动和运行。您还可以选择使用 spring-boot-starter-webflux 模块来构建反应式 Web 应用程序。

    1. Servlet Web 应用程序

    如果您想构建基于 servlet 的 Web 应用程序,您可以利用 Spring Boot 的 Spring MVC 或 Jersey 自动配置。

    1.1. Spring Web MVC 框架

    在 Spring Web MVC 框架(通常简称为 Spring MVC )是一个丰富的“模型视图控制器” Web框架。Spring MVC 允许您创建特殊的 @Controller@RestController bean 来处理传入的 HTTP 请求。控制器中的方法通过使用 @RequestMapping 注解映射到 HTTP 请求。

    以下代码显示了一个典型的提供 JSON 数据的 @RestController 代码:

    @RestController
    @RequestMapping("/users")
    public class MyRestController {
    
        private final UserRepository userRepository;
    
        private final CustomerRepository customerRepository;
    
        public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
            this.userRepository = userRepository;
            this.customerRepository = customerRepository;
        }
    
        @GetMapping("/{userId}")
        public User getUser(@PathVariable Long userId) {
            return this.userRepository.findById(userId).get();
        }
    
        @GetMapping("/{userId}/customers")
        public List<Customer> getUserCustomers(@PathVariable Long userId) {
            return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
        }
    
        @DeleteMapping("/{userId}")
        public void deleteUser(@PathVariable Long userId) {
            this.userRepository.deleteById(userId);
        }
    
    }
    

    功能变体 “WebMvc.fn” 将路由配置与请求的实际处理分开,如下例所示:

    @Configuration(proxyBeanMethods = false)
    public class MyRoutingConfiguration {
    
        private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
    
        @Bean
        public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {
            return route()
                    .GET("/{user}", ACCEPT_JSON, userHandler::getUser)
                    .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
                    .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
                    .build();
        }
    
    }
    
    @Component
    public class MyUserHandler {
    
        public ServerResponse getUser(ServerRequest request) {
            ...
            return ServerResponse.ok().build();
        }
    
        public ServerResponse getUserCustomers(ServerRequest request) {
            ...
            return ServerResponse.ok().build();
        }
    
        public ServerResponse deleteUser(ServerRequest request) {
            ...
            return ServerResponse.ok().build();
        }
    
    }
    

    Spring MVC 是核心 Spring Framework 的一部分,详细信息可在 参考文档 中找到。spring.io/guides 上还有一些涵盖 Spring MVC 的指南。

    您可以定义任意数量的 RouterFunction bean 来模块化路由器的定义。如果您需要应用优先级,可以排序 bean

    1.1.1. Spring MVC 自动配置

    Spring Boot 为 Spring MVC 提供了自动配置,适用于大多数应用程序。

    自动配置在 Spring 的默认值之上添加了以下功能:

    • 包含 ContentNegotiatingViewResolverBeanNameViewResolver bean
    • 支持提供服务静态资源,包括对 WebJars 的支持
    • 自动注册 ConverterGenericConverterFormatter beans
    • 支持 HttpMessageConverters
    • 自动注册 MessageCodesResolver
    • 静态 index.html 支持
    • 自动使用 ConfigurableWebBindingInitializer bean

    如果您想保留 Spring Boot MVC 功能,并且进行更多 MVC 自定义(拦截器,格式化器,视图控制器和其他功能),则可以添加带 @Configuration 注解的 WebMvcConfigurer 类,但不添加 @EnableWebMvc

    如果您希望提供自定义 RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver 实例,则可以声明一个 WebMvcRegistrationsAdapter 实例来提供此类组件。

    如果您想完全控制 Spring MVC ,可以添加自己的带 @EnableWebMvc 注解的 @Configuration 类。

    Spring MVC 使用与用于从您的 application.propertiesapplication.yaml 文件转换值的不同的 ConversionService 。这意味着 Period , DurationDataSize 转换器不可用,并且 @DurationUnit@DataSizeUnit 注解将被忽略。

    如果要自定义 Spring MVC 使用的 ConversionService ,可以提供一个带有 addFormatters 方法的 WebMvcConfigurer bean 。通过这个方法,你可以注册任何你喜欢的转换器,或者你可以委托给 ApplicationConversionService 上的静态方法

    参考源码:

    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
    

    1.1.2. HttpMessageConverters

    Spring MVC 使用 HttpMessageConverter 接口来转换 HTTP 请求和响应。明智的默认设置是开箱即用的。例如,可以将对象自动转换为 JSON(通过使用 Jackson 库)或 XML (通过使用 Jackson XML 扩展,如果可用。或通过使用 JAXB,如果 Jackson XML 扩展不可用)。默认情况下,字符串编码为 UTF-8

    参考源码:

    org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#addDefaultHttpMessageConverters
    

    如果您需要添加或自定义转换器,则可以使用 Spring Boot 的 HttpMessageConverters 类,如下所示:

    import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.converter.HttpMessageConverter;
    
    @Configuration(proxyBeanMethods = false)
    public class MyHttpMessageConvertersConfiguration {
    
        @Bean
        public HttpMessageConverters customConverters() {
            HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
            HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
            return new HttpMessageConverters(additional, another);
        }
    
    }
    

    上下文中存在的任何 HttpMessageConverter bean 都将添加到转换器列表中。您也可以用相同的方法覆盖默认转换器。

    1.1.3. 自定义 JSON 序列化器和反序列化器

    如果使用 Jackson 来序列化和反序列化 JSON 数据,则可能需要编写自己的 JsonSerializerJsonDeserializer 类。自定义序列化器通常是通过模块向 Jackson 进行注册,但是 Spring Boot 提供了另一种选择,使用 @JsonComponent 注解直接注册 Spring Bean 。

    您可以使用 @JsonComponent 直接注解 JsonSerializerJsonDeserializerKeyDeserializer 实现。您还可以在包含序列化器/反序列化器作为内部类的类上使用 @JsonComponent ,如以下示例所示:

    import java.io.IOException;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.ObjectCodec;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    import org.springframework.boot.jackson.JsonComponent;
    
    @JsonComponent
    public class MyJsonComponent {
    
        public static class Serializer extends JsonSerializer<MyObject> {
    
            @Override
            public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
                jgen.writeStartObject();
                jgen.writeStringField("name", value.getName());
                jgen.writeNumberField("age", value.getAge());
                jgen.writeEndObject();
            }
    
        }
    
        public static class Deserializer extends JsonDeserializer<MyObject> {
    
            @Override
            public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt)
                    throws IOException, JsonProcessingException {
                ObjectCodec codec = jsonParser.getCodec();
                JsonNode tree = codec.readTree(jsonParser);
                String name = tree.get("name").textValue();
                int age = tree.get("age").intValue();
                return new MyObject(name, age);
            }
    
        }
    
    }
    

    所有 ApplicationContext 中的 @JsonComponent bean 都会自动向 Jackson 注册。因为 @JsonComponent 使用 @Component 进行了元注解,所以适用于通常的组件扫描规则。

    Spring Boot 还提供了 JsonObjectSerializerJsonObjectDeserializer 基类,使用它们来实现 Jackson 序列反序列器更简单。

    上面的例子可以重写为使用 JsonObjectSerializer / JsonObjectDeserializer 如下:

    import java.io.IOException;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.ObjectCodec;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    import org.springframework.boot.jackson.JsonComponent;
    import org.springframework.boot.jackson.JsonObjectDeserializer;
    import org.springframework.boot.jackson.JsonObjectSerializer;
    
    @JsonComponent
    public class MyJsonComponent {
    
        public static class Serializer extends JsonObjectSerializer<MyObject> {
    
            @Override
            protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
                    throws IOException {
                jgen.writeStringField("name", value.getName());
                jgen.writeNumberField("age", value.getAge());
            }
    
        }
    
        public static class Deserializer extends JsonObjectDeserializer<MyObject> {
    
            @Override
            protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
                    JsonNode tree) throws IOException {
                String name = nullSafeValue(tree.get("name"), String.class);
                int age = nullSafeValue(tree.get("age"), Integer.class);
                return new MyObject(name, age);
            }
    
        }
    
    }
    

    1.1.4. MessageCodesResolver

    Spring MVC 有一个生成错误代码的策略,用于从绑定错误中呈现错误消息:MessageCodesResolver 。如果您设置 spring.mvc.message-codes-resolver-format 属性为 PREFIX_ERROR_CODEPOSTFIX_ERROR_CODE ,Spring Boot 会为您创建一个 MessageCodesResolver

    参考源码:org.springframework.validation.DefaultMessageCodesResolver.Format

    1.1.5. 静态内容

    默认情况下,Spring Boot 从类路径中名为 /static(或 /public/resources/META-INF/resources )的目录或 ServletContext 根目录中提供静态内容。它使用 Spring MVC 中的 ResourceHttpRequestHandler ,因此您可以通过添加自己的 WebMvcConfigurer 并覆盖 addResourceHandlers 方法来修改该行为。

    在独立的 Web 应用程序中,容器中的默认 servlet 也被启用并充当后备,如果 Spring 决定不处理它,则从 ServletContext 根目录提供内容。在大多数情况下,这不会发生(除非您修改默认的 MVC 配置),因为 Spring 始终可以通过 DispatcherServlet 处理请求。

    默认情况下,资源映射到 /** ,但是您可以使用 spring.mvc.static-path-pattern 属性对其进行调整。例如,将所有资源重新定位到 /resources/** ,可以通过以下方式实现:

    spring.mvc.static-path-pattern=/resources/**
    

    参考源码:

    org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#addResourceHandlers
    

    您还可以通过使用 spring.resources.static-locations 属性来自定义静态资源位置(将默认值替换为目录位置列表)。根 Servlet 上下文路径 / ,也会自动被添加为一个位置。

    除了前面提到的“标准”静态资源位置,Webjars 内容也有特殊情况。如果 jar 文件以 Webjars 格式打包,则从 jar 文件提供带有路径 /webjars/** 的所有资源。

    如果您的应用程序打包为 jar ,则不要使用 src/main/webapp 目录。尽管此目录是一个通用标准,但它仅与 war 打包一起使用,如果生成 jar ,大多数构建工具都将其忽略。

    Spring Boot 还支持 Spring MVC 提供的高级资源处理功能,例如缓存清除静态资源或对 Webjars 使用版本无关的URL。

    要对 Webjar 使用版本无关的 URL ,请添加 webjars-locator-core 依赖项。然后声明您的 Webjar 。以 jQuery 为例,将版本为 x.y.z 的 jQuery ,即 /webjars/jquery/x.y.z/jquery.min.js ,添加为 /webjars/jquery/jquery.min.js 结果。

    如果使用 JBoss ,则需要声明 webjars-locator-jboss-vfs 依赖关系而不是 webjars-locator-core 。否则,所有 Webjar 都将解析为 404

    要使用缓存清除,以下配置为所有静态资源配置了缓存清除解决方案,从而有效地在 URL 中添加了内容哈希,例如 <link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>

    spring.resources.chain.strategy.content.enabled=true
    spring.resources.chain.strategy.content.paths=/**
    

    由于为 Thymeleaf 和 FreeMarker 自动配置了 ResourceUrlEncodingFilter ,因此在运行时可以在模板中重写资源链接。使用 JSP 时,您应该手动声明此过滤器。目前尚不自动支持其他模板引擎,但可以与自定义模板宏/帮助程序一起使用,也可以使用ResourceUrlProvider

    例如,当使用 JavaScript 模块加载器动态加载资源时,不能重命名文件。这就是为什么其他策略也受支持并且可以组合的原因。fixed 策略在URL中添加静态版本字符串,而不更改文件名,如以下示例所示:

    spring.resources.chain.strategy.content.enabled=true
    spring.resources.chain.strategy.content.paths=/**
    spring.resources.chain.strategy.fixed.enabled=true
    spring.resources.chain.strategy.fixed.paths=/js/lib/
    spring.resources.chain.strategy.fixed.version=v12
    

    通过这种配置,位于 /js/lib/ 下面的 JavaScript 模块使用 fixed 版本控制策略( /v12/js/lib/mymodule.js ),而其他资源仍使用 content<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>

    更多配置参考

    org.springframework.boot.autoconfigure.web.ResourceProperties
    

    此功能已在专门的 博客文章 和 Spring Framework 的 参考文档 中进行了详细描述

    1.1.6. 欢迎页面

    Spring Boot 支持静态和模板化的欢迎页面。它首先在配置的静态内容位置中查找 index.html 文件。如果未找到,则寻找 index 模板。如果找到任何一个,它将自动用作应用程序的欢迎页面。

    1.1.7. 路径匹配和内容协商

    Spring MVC 可以通过查看请求路径并将其匹配到应用程序中定义的映射(例如,Controller 方法上的 @GetMapping 注解)来将传入的 HTTP 请求映射到处理器。

    Spring Boot 默认选择禁用后缀模式匹配,这意味着类似 GET /projects/spring-boot.json 的请求将不会与 @GetMapping("/projects/spring-boot") 映射匹配。这被认为是 Spring MVC 应用程序的最佳实践。过去,此功能主要用于未发送正确 Accept 请求标头的 HTTP 客户端。我们需要确保将正确的内容类型发送给客户端。如今,内容协商已变得更加可靠。

    还有其他处理不能始终发送正确的 Accept 请求标头的 HTTP 客户端的方法。除了使用后缀匹配,我们还可以使用查询参数来确保将诸如 GET /projects/spring-boot?format=json 这样的请求映射到 @GetMapping("/projects/spring-boot")

    # 是否以请求参数(默认是format)决定请求的内容类型
    spring.mvc.contentnegotiation.favor-parameter=true
    

    或者,如果您更喜欢使用不同的参数名称:

    # 是否以请求参数(默认是format)决定请求的内容类型
    spring.mvc.contentnegotiation.favor-parameter=true
    # 修改默认参数,默认为format
    spring.mvc.contentnegotiation.parameter-name=myparam
    

    大多数标准媒体类型都支持开箱即用,但您也可以定义新的媒体类型:

    # 注册额外的文件扩展名
    spring.mvc.contentnegotiation.media-types.markdown=text/markdown
    

    后缀模式匹配已弃用,并将在未来版本中删除。如果您了解这些警告,并且仍然希望您的应用程序使用后缀模式匹配,则需要以下配置:

    spring.mvc.contentnegotiation.favor-path-extension=true
    spring.mvc.pathmatch.use-suffix-pattern=true
    

    另外,与其打开所有后缀模式,不如仅支持已注册的后缀模式,这会更安全:

    spring.mvc.contentnegotiation.favor-path-extension=true
    spring.mvc.pathmatch.use-registered-suffix-pattern=true
    

    从 Spring Framework 5.3 开始,Spring MVC 支持多种实现策略,用于将请求路径匹配到 Controller 处理器。它以前只支持 AntPathMatcher 策略,但现在它也提供 PathPatternParser 。Spring Boot 现在提供了一个配置属性来选择和使用新策略:

    spring.mvc.pathmatch.matching-strategy=path-pattern-parser
    

    有关为什么应该考虑这个新实现的更多详细信息,请参阅 专门的博客文章

    PathPatternParser 是一种优化的实现,但限制了 某些路径模式变体 的使用, 并且与后缀模式匹配 ( spring.mvc.pathmatch.use-suffix-pattern , spring.mvc.pathmatch.use-registered-suffix-pattern ) 或使用 servlet 前缀 ( spring.mvc.servlet.path ) 映射 DispatcherServlet 不兼容

    1.1.8. ConfigurableWebBindingInitializer

    Spring MVC 为特殊的请求使用 WebBindingInitializer 初始化 WebDataBinder 。如果创建自己的 ConfigurableWebBindingInitializer @Bean,Spring Boot 会自动将 Spring MVC 配置为使用它。

    1.1.9. 模板引擎

    除了 REST Web 服务之外,您还可以使用 Spring MVC 来提供动态 HTML 内容。Spring MVC 支持各种模板技术,包括 Thymeleaf ,FreeMarker 和 JSP 。同样,许多其他模板引擎包括他们自己的 Spring MVC 集成。

    Spring Boot 包含对以下模板引擎的自动配置支持:

    应避免使用 JSP 。将它们与嵌入式 servlet 容器一起使用时,存在一些 已知的限制

    在默认配置下使用这些模板引擎之一时,将从 src/main/resources/templates 中自动提取模板。

    根据您运行应用程序的方式,您的 IDE 可能会以不同的方式对类路径进行排序。在 IDE 中从 main 方法运行应用程序会导致与使用 Maven 或 Gradle 或从其打包的 jar 运行应用程序时不同的顺序。这可能会导致 Spring Boot 无法找到预期的模板。如果您有这个问题,您可以在 IDE 中重新排序类路径以首先放置模块的类和资源

    1.1.10. 错误处理

    默认情况下,Spring Boot提供了 /error 映射所有错误,并且已在 servlet 容器中注册为“全局”错误页面。对于移动客户端,它将生成一个 JSON 响应,其中包含错误详情,HTTP 状态和异常消息的详细信息。对于浏览器客户端,存在一个 whitelabel 错误视图,该视图以 HTML 格式呈现相同的数据(要对其进行自定义,请添加 View 解析为 error )。

    如果要自定义默认错误处理行为,可以设置许多 server.error 属性。请参阅附录的 服务器属性 部分。

    要完全替换默认行为,可以实现 ErrorController 并注册该类型的 bean 定义,或添加 ErrorAttributes 类型的 bean 以使用现有机制但替换内容。

    BasicErrorController 可以用作基类来自定义 ErrorController 。如果您要为新的内容类型添加 handler(默认专门处理 text/html 并为其他所有内容提供备用功能),则此功能特别有用。为此,请扩展 BasicErrorController ,添加一个具有 produces 属性的 @RequestMapping 公共方法,并创建一个新类型的 bean

    您还可以定义带有 @ControllerAdvice 注解的类,以自定义 JSON 文档以针对特定的控制器或异常类型返回,如以下示例所示:

    import javax.servlet.RequestDispatcher;
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
    
    @ControllerAdvice(basePackageClasses = SomeController.class)
    public class MyControllerAdvice extends ResponseEntityExceptionHandler {
    
        @ResponseBody
        @ExceptionHandler(MyException.class)
        public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
            HttpStatus status = getStatus(request);
            return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);
        }
    
        private HttpStatus getStatus(HttpServletRequest request) {
            Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
            HttpStatus status = HttpStatus.resolve(code);
            return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;
        }
    
    }
    

    在前面的示例中,如果由与 YourException 相同的包中定义的控制器 SomeController 抛出,则使用 CustomErrorType POJO 的 JSON 表示而不是 ErrorAttributes 表示。

    在某些情况下,在控制器级别处理的错误不会被 度量(metrics)基础设施 记录。应用程序可以通过将处理的异常设置为请求属性来确保将此类异常与请求指标(metrics)一起记录:

    @Controller
    public class MyController {
    
        @ExceptionHandler(CustomException.class)
        String handleCustomException(HttpServletRequest request, CustomException ex) {
            request.setAttribute(ErrorAttributes.ERROR_ATTRIBUTE, ex);
            return "errorView";
        }
    
    }
    
    自定义错误页面

    如果要显示给定状态代码的自定义 HTML 错误页面,可以将文件添加到 /error 目录。错误页面可以是静态 HTML(即添加到任何静态资源文件夹下),也可以使用模板来构建。文件名应为准确的状态代码或序列掩码。

    例如,要映射 404 到静态 HTML 文件,您的文件夹结构如下:

    src/
        +- main/
            +- java/
            | + <source code>
            +- resources/
                +- public/
                    +- error/
                    | +- 404.html
                    +- <other public assets>
    

    要使用 FreeMarker 模板映射所有 5xx 错误,您的目录结构如下:

    src/
     +- main/
         +- java/
         |   + <source code>
         +- resources/
             +- templates/
                 +- error/
                 |   +- 5xx.ftlh
                 +- <other templates>
    

    对于更复杂的映射,还可以添加实现 ErrorViewResolver 接口的 bean ,如以下示例所示:

    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
    import org.springframework.http.HttpStatus;
    import org.springframework.web.servlet.ModelAndView;
    
    public class MyErrorViewResolver implements ErrorViewResolver {
    
        @Override
        public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
            // Use the request or status to optionally return a ModelAndView
            if (status == HttpStatus.INSUFFICIENT_STORAGE) {
                // We could add custom model values here
                new ModelAndView("myview");
            }
            return null;
        }
    
    }
    

    您还可以使用常规的 Spring MVC 功能,例如 @ExceptionHandler 方法@ControllerAdviceErrorController 随后处理任何未处理的异常。

    在 Spring MVC 之外映射错误页面

    对于不使用 Spring MVC 的应用程序,您可以使用 ErrorPageRegistrar 接口直接注册 ErrorPages 。此抽象直接与底层的嵌入式 servlet 容器一起工作,即使您没有 Spring MVC 也可以使用 DispatcherServlet

    import org.springframework.boot.web.server.ErrorPage;
    import org.springframework.boot.web.server.ErrorPageRegistrar;
    import org.springframework.boot.web.server.ErrorPageRegistry;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpStatus;
    
    @Configuration(proxyBeanMethods = false)
    public class MyErrorPagesConfiguration {
    
        @Bean
        public ErrorPageRegistrar errorPageRegistrar() {
            return this::registerErrorPages;
        }
    
        private void registerErrorPages(ErrorPageRegistry registry) {
            registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
        }
    
    }
    

    如果您使用最终由 Filter 处理的路径注册 ErrorPage(这在某些非 Spring Web 框架中很常见,例如 Jersey 和 Wicket ),则 Filter 必须将其显式注册为 ERROR 调度器,如以下示例所示:

    import java.util.EnumSet;
    
    import javax.servlet.DispatcherType;
    
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration(proxyBeanMethods = false)
    public class MyFilterConfiguration {
    
        @Bean
        public FilterRegistrationBean<MyFilter> myFilter() {
            FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(new MyFilter());
            // ...
            registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
            return registration;
        }
    
    }
    

    请注意,默认的 FilterRegistrationBean 不包括 ERROR 调度器类型。

    war 部署中的错误处理

    当部署到 servlet 容器时,Spring Boot 使用其错误页面过滤器将具有错误状态的请求转发到相应的错误页面。这是必要的,因为 servlet 规范不提供用于注册错误页面的 API。根据您将 war 文件部署到的容器以及您的应用程序使用的技术,可能需要一些额外的配置。

    如果响应尚未提交,错误页面过滤器只能将请求转发到正确的错误页面。默认情况下,WebSphere Application Server 8.0 和更高版本在成功完成 servlet 的服务方法时提交响应。您应该通过设置 com.ibm.ws.webcontainer.invokeFlushAfterServicefalse 来禁用此行为

    如果您使用 Spring Security 并希望在错误页面中访问主体,则必须配置 Spring Security 的过滤器以在错误调度时调用。为此,请将 spring.security.filter.dispatcher-types 属性设置为 async, error, forward, request

    1.1.11. CORS 支持

    跨域资源共享(CORS) 是由大多数浏览器实施的 W3C 规范,可让您灵活地指定授权哪种类型的跨域请求,而不是使用诸如 IFRAME 或 JSONP 之类的安全性较低,功能较弱的方法。

    从 4.2 版本开始,Spring MVC 支持 CORS 。在 Spring Boot 应用程序中使用带有 @CrossOrigin 注解的 CORS 配置的控制器方法不需要任何特定的配置。可以通过使用自定义方法 WebMvcConfigurer#addCorsMappings(CorsRegistry) 来定义 全局 CORS 配置 ,如以下示例所示:

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration(proxyBeanMethods = false)
    public class MyCorsConfiguration {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurer() {
    
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/api/**");
                }
    
            };
        }
    
    }
    

    1.2. JAX-RS 和 Jersey

    如果您更喜欢 REST 端点的 JAX-RS 编程模型,可以使用可用的实现之一来代替 Spring MVC 。 JerseyApache CXF 开箱即用。CXF 需要您在应用上下文注册其 Servlet 或 Filter 为 @Bean 。Jersey 提供了一些原生的 Spring 支持,所以我们还在 Spring Boot 中为它提供了自动配置支持,以及一个 Starter 。

    要开始使用 Jersey ,请包含 spring-boot-starter-jersey 为依赖项,然后需要使用 ResourceConfig 类型 @Bean 注册所有端点,如以下示例所示:

    import org.glassfish.jersey.server.ResourceConfig;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyJerseyConfig extends ResourceConfig {
    
        public MyJerseyConfig() {
            register(MyEndpoint.class);
        }
    
    }
    

    Jersey 对扫描可执行文档的支持相当有限。例如,当运行一个可执行的 war 文件时,它不能扫描在 完全可执行的 jar 文件WEB-INF/classes 中找到的包中的端点。为了避免这个限制,不应该使用 packages 方法,应该使用 register 方法单独注册端点,如前面的示例所示。

    对于更高级的自定义,您还可以注册任意数量的实现 ResourceConfigCustomizer 的 bean

    所有注册的端点都应带有 @Components 和 HTTP 资源注解( @GET 及其他注解),如以下示例所示:

    @Component
    @Path("/hello")
    public class Endpoint {
        @GET
        public String message() {
            return "Hello";
        }
    }
    

    由于 Endpoint 是 Spring @Component ,因此其生命周期由 Spring 管理,您可以使用 @Autowired 注解注入依赖项,并使用 @Value 注解注入外部配置。默认情况下,Jersey servlet 已注册并映射到 /* 。您可以通过在 ResourceConfig 添加 @ApplicationPath 改变映射。

    默认情况下,Jersey 被设置为一个类型是 ServletRegistrationBean ,命名为 jerseyServletRegistration 的 Servlet 的 @Bean 。默认情况下,该 Servlet 延迟初始化,但是您可以通过设置 spring.jersey.servlet.load-on-startup 来自定义该行为。您可以通过创建自己的同名 bean 来禁用或覆盖该 bean 。您还可以通过设置 spring.jersey.type=filter 使用 Filter 而不是 Servlet(在这种情况下,要替换或覆盖的是 jerseyFilterRegistration @Bean )。过滤器具有 @Order ,您可以使用 spring.jersey.filter.order 设置。可以通过 spring.jersey.init.* 指定属性映射来为 servlet 和过滤器注册都赋予初始化参数。

    1.3. 嵌入式 Servlet 容器支持

    Spring Boot 包含对嵌入式 TomcatJettyUndertow 服务器的支持。大多数开发人员使用适当的 Starter 来获取完全配置的实例。默认情况下,嵌入式服务器在监听 8080 端口。

    1.3.1. Servlet,Filter 和 Lisener

    使用嵌入式 Servlet 容器时,您可以使用 Spring bean 或扫描 Servlet 组件来注册 ServletFilter 和 Servlet 规范中的所有 Lisener(例如 HttpSessionListener )。

    将 Servlet ,Filter 和 Lisener 注册为 Spring bean

    作为 Spring bean 的任何 Servlet,Filter 或 servlet *Listener 实例都向嵌入式容器注册。如果要在配置 application.properties 过程中引用一个值,这将特别方便。

    默认情况下,如果上下文仅包含单个 Servlet ,则将其映射到 / 。对于多个 servlet bean ,bean 名称用作路径前缀。

    Filter 映射到 /*

    如果基于约定的映射不够灵活,你可以使用 ServletRegistrationBeanFilterRegistrationBean 以及 ServletListenerRegistrationBean 类进行完全控制。

    Filter bean 无序通常是安全的。可以添加 @Order 注解或实现 Ordered 接口,以控制其在过滤链中的位置。您不能通过使用 @Order 注解其 bean 方法来配置 Filter 的顺序。如果您无法更改要添加 @Order 或实现 OrderedFilter 类,则必须为 Filter 定义一个 FilterRegistrationBean 并使用 setOrder(int) 方法设置注册 bean 的顺序。

    应避免配置一个读取请求正文的过滤器为 Ordered.HIGHEST_PRECEDENCE ,因为它可能与应用程序的字符编码配置相冲突。如果 Servlet Filter 包装了请求,则应以小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER 的顺序对其进行配置。

    要查看应用程序中每个 Filter 组件的顺序,请为 web 日志记录组 启用 debug 级别的日志记录( logging.level.web=debug )。然后,将在启动时记录已注册 Filter 的详细信息,包括其顺序和 URL 模式。

    注册 Filter bean 时要小心,因为它们是在应用程序生命周期中很早就初始化的。如果您需要注册一个 Filter 与其他 bean 交互的,请考虑使用 DelegatingFilterProxyRegistrationBean

    1.3.2. Servlet 上下文初始化

    嵌入式 Servlet 容器不会直接执行 Servlet 3.0+ 的 javax.servlet.ServletContainerInitializer 接口或 Spring 的 org.springframework.web.WebApplicationInitializer 接口。这是一个有意的设计决策,旨在降低在 war 中运行的第三方库可能破坏 Spring Boot 应用程序的风险。

    如果您需要在 Spring Boot 应用程序中执行 servlet 上下文初始化,则应该注册一个实现 org.springframework.boot.web.servlet.ServletContextInitializer 接口的 bean 。onStartup 方法提供对 ServletContext 的访问,并且在必要时可以轻松用作现有 WebApplicationInitializer 的适配器。

    扫描 Servlet ,Filter 和 Listener

    当使用嵌入式容器中,可以通过使用 @ServletComponentScan 启用对 @WebServlet@WebFilter@WebListener 的自动注册。

    @ServletComponentScan 在独立的容器中无效,而是应该使用容器的内置发现机制。

    1.3.3. ServletWebServerApplicationContext

    在底层,Spring Boot 对嵌入式 servlet 容器使用了不同类型的 ApplicationContext 支持。ServletWebServerApplicationContext 是一种特殊类型的 WebApplicationContext ,通过搜索单个 ServletWebServerFactory bean 引导自身。通常是已被自动配置的 TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory

    通常,您不需要了解这些实现类。大多数应用程序都自动配置,并且适当的 ApplicationContextServletWebServerFactory 已创建。

    在嵌入式容器设置中,ServletContext 设置为在应用上下文初始化期间发生的服务器启动的一部分。因为 ApplicationContext 中的这个 bean 不能用 ServletContext 进行可靠的初始化。解决此问题的一种方法是将注入 ApplicationContext 作为 bean 的依赖项并仅在需要时访问 ServletContext 。另一种方法是在服务器启动后使用回调。这可以通过监听 ApplicationStartedEvent 事件的 ApplicationListener 来完成:

    import javax.servlet.ServletContext;
    
    import org.springframework.boot.context.event.ApplicationStartedEvent;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationListener;
    import org.springframework.web.context.WebApplicationContext;
    
    public class MyDemoBean implements ApplicationListener<ApplicationStartedEvent> {
    
        private ServletContext servletContext;
    
        @Override
        public void onApplicationEvent(ApplicationStartedEvent event) {
            ApplicationContext applicationContext = event.getApplicationContext();
            this.servletContext = ((WebApplicationContext) applicationContext).getServletContext();
        }
    
    }
    

    1.3.4. 自定义嵌入式 Servlet 容器

    可以使用 Spring Environment 属性来配置常见的 servlet 容器设置。通常,您将在 application.propertiesapplication.yaml 文件中定义属性。

    常见的服务器设置包括:

    • 网络设置:监听传入 HTTP 请求的端口( server.port ),要绑定到的接口地址( server.address ),等等
    • 会话设置:会话是否为持久( server.servlet.session.persistent ),会话超时( server.servlet.session.timeout ),会话数据保存位置( server.servlet.session.store-dir )和会话 Cookie 配置( server.servlet.session.cookie.*
    • 错误管理:错误页面的位置( server.error.path )等
    • SSL
    • HTTP 压缩

    Spring Boot尝试尽可能多地公开通用设置,但这并不总是可能的。在这种情况下,专用名称空间提供特定于服务器的定制属性(请参阅 server.tomcatserver.undertow )。例如,可以使用嵌入式 servlet 容器的特定功能配置 访问日志

    更多配置参考:

    org.springframework.boot.autoconfigure.web.ServerProperties
    

    Web 浏览器可以使用 SameSite Cookie 属性来控制是否以及如何在跨站点请求中提交 Cookie 。该属性与现代 Web 浏览器特别相关,这些浏览器已开始更改缺少该属性时使用的默认值。

    如果要更改会话 Cookie 的 SameSite 属性,可以使用 server.servlet.session.cookie.same-site 属性。自动配置的 Tomcat 、Jetty 和 Undertow 服务器支持此属性。它还用于配置基于 SessionRepository bean 的 Spring Session servlet 。

    例如,如果您希望会话 Cookie 具有 SameSite 属性 None ,您可以将以下内容添加到您的 application.propertiesapplication.yaml 文件中:

    server.servlet.session.cookie.same-site=none
    

    如果您想更改添加到您的 HttpServletResponse 上其他 Cookie 的 SameSite 属性,您可以使用 CookieSameSiteSupplierCookieSameSiteSupplier 传递了一个 Cookie 并且可能返回一个 SameSite 值,或者 null

    您可以使用许多便利工厂和过滤器方法来快速匹配特定的 Cookie 。例如,添加下面的 bean 将自动为所有名称与正则表达式 myapp.* 匹配的 Cookie 应用一个 LaxSameSite

    import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration(proxyBeanMethods = false)
    public class MySameSiteConfiguration {
    
        @Bean
        public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
            return CookieSameSiteSupplier.ofLax().whenHasNameMatching("myapp.*");
        }
    
    }
    

    以编程方式定制

    如果需要以编程方式配置嵌入式 servlet 容器,则可以注册一个实现 WebServerFactoryCustomizer 接口的 Spring bean 。 WebServerFactoryCustomizer 提供对 ConfigurableServletWebServerFactory 的访问,其中包括许多自定义 setter 方法。以下示例显示以编程方式设置端口:

    import org.springframework.boot.web.server.WebServerFactoryCustomizer;
    import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class MyWebServerFactoryCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
    
        @Override
        public void customize(ConfigurableServletWebServerFactory server) {
            server.setPort(9000);
        }
    
    }
    

    TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactoryConfigurableServletWebServerFactory 的专用变体,具有分别用于 Tomcat , Jetty 和 Undertow 的额外定制 setter 方法。

    以下示例显示了如何自定义 TomcatServletWebServerFactory 以提供对特定于 Tomcat 的配置选项的访问:

    @Component
    public class MyTomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
        @Override
        public void customize(TomcatServletWebServerFactory server) {
            server.addConnectorCustomizers((connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));
        }
    
    }
    

    直接自定义 ConfigurableServletWebServerFactory

    对于需要从 ServletWebServerFactory 扩展的更高级的用例,您可以自己公开这种类型的 bean 。

    为许多配置选项提供了 setter 。如果您需要做一些更奇特的事情,还提供了几个受保护的方法“钩子”。有关详细信息,请参阅 源代码文档

    1.3.5. JSP 局限性

    运行使用嵌入式 servlet 容器(并打包为可执行 Jar )的 Spring Boot 应用程序时,JSP 支持存在一些限制

    • 对于 Jetty 和 Tomcat ,如果使用 war 打包,它应该可以工作。使用 java -jar 启动时,可执行的 war 将起作用,并且也可部署到任何标准容器中。使用可执行 jar 时,不支持 JSP
    • Undertow 不支持 JSP
    • 创建自定义 error.jsp 页面不会覆盖 错误处理 的默认视图。 应改用 自定义错误页面

    2. 反应式 Web 应用程序 todo

    3. 优雅关闭

    所有四个嵌入式 Web 服务器( Jetty、Reactor Netty、Tomcat 和 Undertow )以及反应式和基于 servlet 的 Web 应用程序都支持优雅关闭。它作为关闭应用上下文的一部分发生,并在停止 SmartLifecycle bean 的最早阶段执行。此停止处理使用超时提供宽限期,在此期间将允许完成现有请求,但不允许新请求。不允许新请求的确切方式因所使用的 Web 服务器而异。Jetty、Reactor Netty 和 Tomcat 将停止接受网络层的请求。Undertow 将接受请求,但会立即以服务不可用 ( 503 ) 进行响应。

    使用 Tomcat 优雅关闭需要 Tomcat 9.0.33 或更高版本。

    要启用优雅关闭,请配置 server.shutdown 属性,如以下示例所示:

    server.shutdown=graceful
    

    要配置超时时间,请配置 spring.lifecycle.timeout-per-shutdown-phase 属性,如以下示例所示:

    spring.lifecycle.timeout-per-shutdown-phase=20s
    

    如果没有发送正确的 SIGTERM 信号,则对 IDE 使用优雅关闭可能无法正常工作。有关更多详细信息,请参阅 IDE 的文档。

    4. Spring Security

    如果 Spring Security 在类路径上,则默认情况下 Web 应用程序是安全的。Spring Boot 依赖 Spring Security 的内容协商策略来确定是否使用 httpBasicformLogin 。要为 Web 应用程序添加方法级别的安全,您还可以添加 @EnableGlobalMethodSecurity 所需的设置。更多信息可以在 Spring Security Reference Guide 中找到。

    默认 UserDetailsService 只有一个用户。用户名为 user ,密码是随机的,在应用启动时打印在 WARN 级别,如下例所示:

    Using generated security password: 78fa095d-3f4c-48b1-ad50-e24c31d5cf35
    
    This generated password is for development use only. Your security configuration must be updated before running your application in production.
    

    如果您微调日志配置,请确保将 org.springframework.boot.autoconfigure.security 设置为日志 WARN 级别消息。否则,不会打印默认密码。

    您可以通过提供 spring.security.user.namespring.security.user.password 来更改用户名和密码。

    默认情况下,您在 Web 应用程序中获得的基本功能是:

    • UserDetailsService(或 ReactiveUserDetailsService ,在 WebFlux 应用程序的情况下)具有内存存储的 bean 和具有生成密码的单个用户(请参阅用户属性 SecurityProperties.User
    • 整个应用程序(包括执行器端点,如果执行器位于类路径上)的基于表单的登录或 HTTP 基本安全性(取决于请求中的 Accept 标头)
    • DefaultAuthenticationEventPublisher 用于发布身份验证事件

    您可以通过为其添加 bean 来提供不同的 AuthenticationEventPublisher

    4.1. MVC Security

    默认安全配置在 SecurityAutoConfigurationUserDetailsServiceAutoConfiguration 中实现。 SecurityAutoConfiguration 导入用于 web 安全的 SpringBootWebSecurityConfigurationUserDetailsServiceAutoConfiguration 配置身份验证,这也与非 web 应用程序相关。要完全关闭默认的 Web 应用程序安全配置或组合多个 Spring Security 组件(例如 OAuth2 客户端和资源服务器),请添加一个 SecurityFilterChain 类型的 bean (这样做不会禁用 UserDetailsService 配置或执行器( Actuator )的安全性)。

    要关闭 UserDetailsService 配置,您可以添加类型为 UserDetailsServiceAuthenticationProviderAuthenticationManager 的 bean 。

    可以通过添加自定义 SecurityFilterChainWebSecurityConfigurerAdapter bean 来覆盖访问规则。Spring Boot 提供了方便的方法,可用于覆盖执行器端点和静态资源的访问规则。 EndpointRequest 可用于创建基于 management.endpoints.web.base-path 属性的 RequestMatcher 。 可以使用 PathRequest 为常用位置中的资源创建 RequestMatcher

    4.2. WebFlux Security todo

    4.3. OAuth2

    OAuth2 是 Spring 支持的广泛使用的授权框架。

    4.3.1. Client

    如果类路径上有 spring-security-oauth2-client ,则可以利用一些自动配置来设置 OAuth2/Open ID Connect 客户端。此配置使用 OAuth2ClientProperties 里的属性。相同的属性适用于 servlet 和响应式应用程序。

    您可以在 spring.security.oauth2.client 前缀下注册多个 OAuth2 客户端和供应商,如下例所示:

    spring.security.oauth2.client.registration.my-client-1.client-id=abcd
    spring.security.oauth2.client.registration.my-client-1.client-secret=password
    spring.security.oauth2.client.registration.my-client-1.client-name=Client for user scope
    spring.security.oauth2.client.registration.my-client-1.provider=my-oauth-provider
    spring.security.oauth2.client.registration.my-client-1.scope=user
    spring.security.oauth2.client.registration.my-client-1.redirect-uri=https://my-redirect-uri.com
    spring.security.oauth2.client.registration.my-client-1.client-authentication-method=basic
    spring.security.oauth2.client.registration.my-client-1.authorization-grant-type=authorization-code
    
    spring.security.oauth2.client.registration.my-client-2.client-id=abcd
    spring.security.oauth2.client.registration.my-client-2.client-secret=password
    spring.security.oauth2.client.registration.my-client-2.client-name=Client for email scope
    spring.security.oauth2.client.registration.my-client-2.provider=my-oauth-provider
    spring.security.oauth2.client.registration.my-client-2.scope=email
    spring.security.oauth2.client.registration.my-client-2.redirect-uri=https://my-redirect-uri.com
    spring.security.oauth2.client.registration.my-client-2.client-authentication-method=basic
    spring.security.oauth2.client.registration.my-client-2.authorization-grant-type=authorization_code
    
    spring.security.oauth2.client.provider.my-oauth-provider.authorization-uri=https://my-auth-server/oauth/authorize
    spring.security.oauth2.client.provider.my-oauth-provider.token-uri=https://my-auth-server/oauth/token
    spring.security.oauth2.client.provider.my-oauth-provider.user-info-uri=https://my-auth-server/userinfo
    spring.security.oauth2.client.provider.my-oauth-provider.user-info-authentication-method=header
    spring.security.oauth2.client.provider.my-oauth-provider.jwk-set-uri=https://my-auth-server/token_keys
    spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=name
    

    对于支持 OpenID Connect 发现 的 OpenID Connect 供应商,可以进一步简化配置。供应商需要配置 issuer-uri URI,声明为它的颁发者标识符。例如,如果 issuer-uri 提供的是 https://example.com ,那么 OpenID Provider Configuration Request 将对 https://example.com/.well-known/openid-configuration 进行设置。结果预计为 OpenID Provider Configuration Response 。以下示例显示了如何使用 issuer-uri 配置 OpenID Connect 供应商:

    spring.security.oauth2.client.provider.oidc-provider.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
    

    默认情况下,Spring Security OAuth2LoginAuthenticationFilter 只处理匹配 /login/oauth2/code/* 的 URL 。如果要自定义 redirect-uri 以使用不同的模式,则需要提供配置来处理该自定义模式。例如,对于 servlet 应用程序,您可以添加自己的 SecurityFilterChain

    @Configuration(proxyBeanMethods = false)
    public class MyOAuthClientConfiguration {
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated();
            http.oauth2Login().redirectionEndpoint().baseUri("custom-callback");
            return http.build();
        }
    
    }
    

    Spring Boot 自动配置 Spring Security 用于管理客户端注册的 InMemoryOAuth2AuthorizedClientServiceInMemoryOAuth2AuthorizedClientService 功能有限,我们建议仅将其用于开发环境。对于生产环境,请考虑使用 JdbcOAuth2AuthorizedClientService 或创建您自己的 OAuth2AuthorizedClientService

    4.3.2. Resource Server

    如果你的类路径上有 spring-security-oauth2-resource-server ,Spring Boot 可以设置一个 OAuth2 资源服务器。对于 JWT 配置,需要指定 JWK Set URI 或 OIDC Issuer URI ,如以下示例所示:

    spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://example.com/oauth2/default/v1/keys
    
    spring.security.oauth2.resourceserver.jwt.issuer-uri=https://dev-123456.oktapreview.com/oauth2/default/
    

    如果授权服务器不支持 JWK Set URI,您可以为资源服务器配置用于验证 JWT 签名的公钥。这可以使用 spring.security.oauth2.resourceserver.jwt.public-key-location 属性来完成,其中值需要指向包含 PEM 编码 x509 格式的公钥的文件

    相同的属性适用于 servlet 和响应式应用程序。

    或者,您可以为 servlet 应用程序或响应式应用程序定义自己的 JwtDecoderReactiveJwtDecoder bean

    在使用不透明令牌而不是 JWT 的情况下,您可以配置以下属性以通过自省来验证令牌:

    spring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://example.com/check-token
    spring.security.oauth2.resourceserver.opaquetoken.client-id=my-client-id
    spring.security.oauth2.resourceserver.opaquetoken.client-secret=my-client-secret
    

    同样,相同的属性适用于 servlet 和响应式应用程序。

    或者,您可以为 servlet 应用程序或响应式应用程序定义自己的 OpaqueTokenIntrospectorReactiveOpaqueTokenIntrospector bean

    4.3.3. Authorization Server

    目前,Spring Security 不支持实现 OAuth 2.0 授权服务器。但是,此功能可从 Spring Security OAuth 项目中获得,该项目最终将被 Spring Security 完全取代。在此之前,您可以使用 spring-security-oauth2-autoconfigure 模块轻松设置 OAuth 2.0 授权服务器;有关说明,请参阅其 文档

    4.4. SAML 2.0

    4.4.1. Relying Party

    如果您的类路径中有 spring-security-saml2-service-provider ,您可以利用一些自动配置来设置 SAML 2.0 Relying Party 。此配置使用 Saml2RelyingPartyProperties 中的属性

    Relying Party 注册代表 身份提供者( Identity Provider) IDP 和服务提供者(Service Provider) SP 之间的配对配置。您可以在 spring.security.saml2.relyingparty 前缀下注册多个 Relying Party ,如下例所示:

    spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party1.decryption.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.verification.credentials[0].certificate-location=path-to-verification-cert
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.entity-id=remote-idp-entity-id1
    spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.sso-url=https://remoteidp1.sso.url
    
    spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].private-key-location=path-to-private-key
    spring.security.saml2.relyingparty.registration.my-relying-party2.decryption.credentials[0].certificate-location=path-to-certificate
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.verification.credentials[0].certificate-location=path-to-other-verification-cert
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.entity-id=remote-idp-entity-id2
    spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.sso-url=https://remoteidp2.sso.url
    

    5. Spring Session

    Spring Boot 为各种数据存储提供 Spring Session 自动配置。在构建 servlet Web 应用程序时,可以自动配置以下存储:

    • JDBC
    • Redis
    • Hazelcast
    • MongoDB

    此外, Spring Boot for Apache Geode 提供了 将 Apache Geode 用作会话存储的自动配置

    servlet 自动配置取代了使用 @Enable*HttpSession

    在构建响应式 Web 应用程序时,可以自动配置以下存储:

    • Redis
    • MongoDB

    反应式自动配置取代了使用 @Enable*WebSession.

    如果类路径中存在单个 Spring Session 模块,则 Spring Boot 会自动使用该存储实现。如果您有多个实现,则必须选择您希望用来存储会话的那个 StoreType 。例如,要将 JDBC 用作后端存储,您可以按如下方式配置您的应用程序:

    spring.session.store-type=jdbc
    

    您可以通过将 store-type 设置为 none 来禁用 Spring Session

    每个存储都有特定设置。例如,可以为 JDBC 存储自定义配置表的名称,如下例所示:

    spring.session.jdbc.table-name=SESSIONS
    

    要设置会话的超时,您可以使用 spring.session.timeout 属性。如果 servlet web 应用程序没有设置这个属性,那么自动配置将使用后备属性 server.servlet.session.timeout 的值。

    您可以使用 @Enable*HttpSession (servlet) 或 @Enable*WebSession (reactive) 控制 Spring Session 的配置。这将导致自动配置退出。然后可以使用注解的属性而不是前面描述的配置属性来配置 Spring Session。

    6. Spring HATEOAS

    如果您开发使用超媒体的 RESTful API ,Spring Boot 为 Spring HATEOAS 提供自动配置,适用于大多数应用程序。自动配置取代了使用 @EnableHypermediaSupport 和注册许多 bean 以简化构建基于超媒体的应用程序的需要,包括 LinkDiscoverers(用于客户端支持)和 ObjectMapper 配置为将响应正确编组为所需表示的配置。可以通过设置各种 spring.jackson.* 属性来定制 ObjectMapper ,或者,如果存在的话,可以通过 Jackson2ObjectMapperBuilder bean 来定制。

    您可以使用 @EnableHypermediaSupport 来控制 Spring HATEOAS 的配置。请注意,这样做会禁用前面描述的 ObjectMapper 自定义。

    spring-boot-starter-hateoas 特定于 Spring MVC,不应与 Spring WebFlux 结合使用。为了将 Spring HATEOAS 与 Spring WebFlux 一起使用,您可以直接添加依赖:org.springframework.hateoas:spring-hateoasspring-boot-starter-webflux

  • 相关阅读:
    svn更新出错,Previous operation has not finished; run 'cleanup' if it was interrupted
    angular转换日期格式问题
    eclipse自动补全和取消空格自动补全功能
    对枚举和静态常量的理解
    对Spring的IOC、DI、AOP的理解
    maven库因为网络原因jar下载失败
    java new一个对象的过程
    shelve模块读写文件报错
    $http.get(...).then(...).error is not a function
    jQuery动画的先后执行
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/16354169.html
Copyright © 2020-2023  润新知