在 Spring Boot 中从 JWT 安全检查中排除 URL

Posted

技术标签:

【中文标题】在 Spring Boot 中从 JWT 安全检查中排除 URL【英文标题】:Exclude URLs from JWT security check in Spring Boot 【发布时间】:2020-12-09 15:49:49 【问题描述】:

我有一个 Spring Boot 应用程序,我通过将这些依赖项添加到 pom.xml 来使用资源服务器保护它。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency> 

这通常效果很好,但我需要从安全检查中排除特定的 URL,我尝试通过创建我的自定义 WebSecurityConfigurerAdapter 来实现。

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    public void configure(final WebSecurity web) throws Exception 
        web.ignoring().antMatchers("/test");
    

但是,在创建这个类之后,所有调用(除了对 /test 的调用)都会失败,因为服务器会重定向到登录页面。

我的端点如下所示:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class TestController 

    @GetMapping("test") // This endpoint should be ignored
    public String test() 
        return "1.0";
    

    @GetMapping("foo")
    public String test1() 
        return "foo";
    


请求 http://localhost:8080/test 时,我的日志输出如下所示:

2020-08-24 08:48:28.215 DEBUG 7473 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet        : GET "/test", parameters=
2020-08-24 08:48:28.215 DEBUG 7473 --- [nio-8080-exec-5] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to com.test.controllers.TestController#test()
2020-08-24 08:48:28.218 DEBUG 7473 --- [nio-8080-exec-5] m.m.a.RequestResponseBodyMethodProcessor : Using 'text/html', given [text/html, application/xhtml+xml, image/webp, image/apng, application/xml;q=0.9, application/signed-exchange;v=b3;q=0.9, */*;q=0.8] and supported [text/plain, */*, text/plain, */*, application/json, application/*+json, application/json, application/*+json]
2020-08-24 08:48:28.218 DEBUG 7473 --- [nio-8080-exec-5] m.m.a.RequestResponseBodyMethodProcessor : Writing ["1.0"]
2020-08-24 08:48:28.219 DEBUG 7473 --- [nio-8080-exec-5] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

点击端点 http://localhost:8080/foo 将导致重定向到登录页面,并且根本不会有日志输出。

谁能告诉我我错过了什么?如何创建一个除了从安全检查中排除某些 URL 之外什么都不做的 WebSecurityConfigurerAdapter?

请在此处找到一个虚拟项目:https://github.com/paulsasel/spring-boot-jwt-exclude-urls

【问题讨论】:

您能否在重定向发生时在日志中包含您尝试调用的端点以及您收到的任何进一步信息?仅用于“双重检查”,尝试使用自定义 @Override protected void configure(HttpSecurity http) throws Exception(在 JWTSecurityConfig 内) 将日志级别安全设置为 DEBUG(application.properties 添加行logging.level.org.springframework.security=DEBUG)并检查您的测试端点是否被忽略,您应该会看到类似o.s.security.web.FilterChainProxy : /test has an empty filter list 嗨,感谢 cmets。我编辑了问题并添加了日志信息。我还尝试将以下方法添加到我的 JWTSecurityConfig:protected void configure(final HttpSecurity http) throws Exception http.authorizeRequests().antMatchers("/test").permitAll().anyRequest().authenticated();在这种情况下,我在访问 /foo 端点时收到 403 错误页面,但在使用有效 JWT 令牌访问端点时,我也会收到 403 默认情况下,当您拉入 spring security 基本身份验证时,所有端点都处于活动状态。您访问的所有端点都会将您重定向到默认登录页面。您已选择忽略 /test 端点的所有 spring 安全性,以便通过。您的预期行为是什么?使用 JWT?那么你需要禁用基本登录,并配置jwts的使用。 如果你有一个 Github 帐户(或任何其他类似的帐户),最好的选择是将你的项目包含在其中,这样任何人都可以下载它并帮助你以更好的方式了解您的案例中缺少/需要的内容。 【参考方案1】:

如果您忽略 void configure(final WebSecurity web) 中的某些内容,那么它将完全忽略来自过滤器链的请求。见Spring Security Configuration - HttpSecurity vs WebSecurity

但这只是第一部分。还有另一个重载void configure(HttpSecurity http),稍后在链中调用它,它定义了您希望如何保护端点。如果您不覆盖它,则默认为 formLogin,您可以在源代码中看到它:

http
    .authorizeRequests()
        .anyRequest().authenticated()
            .and()
    .formLogin().and()
    .httpBasic();

这就是它会将您重定向到登录页面的原因。

因此,为了使用 JWT 身份验证,您也应该覆盖后者,并定义您要使用 oauth2 资源服务器进行身份验证:

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.cors()
            .and()
            .authorizeRequests()
                .anyRequest()
                    .authenticated()
            .and()
                .oauth2ResourceServer()
                    .jwt();

顺便说一句,您还可以在此处检查角色或请求类型。此外,作为一种替代方法,您也可以在这里忽略 /test 端点,这对我来说是一个更简洁的选择:

@Override
protected void configure(HttpSecurity http) throws Exception 
    http.cors()
            .and()
            .authorizeRequests()
                .antMatchers("/test")
                    .permitAll()
                .antMatchers(HttpMethod.GET, "/foo")
                    .hasAuthority("DUMMYAUTHORITY")
                .anyRequest()
                    .authenticated()
            .and()
                .oauth2ResourceServer()
                    .jwt();

兄弟, 南多尔

【讨论】:

以上是关于在 Spring Boot 中从 JWT 安全检查中排除 URL的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 配置问题中的 JWT 令牌

来自文件的 Spring Boot http 安全 jwt 密钥

在 Spring Boot 安全性中使用公钥/私钥创建和验证 JWT 签名

Spring Boot 安全性 + JWT

使用 Stomp 在 Spring Boot 中访问 JWT 令牌

Spring boot + JWT 实现安全验证 ---auth0.jwt