Spring Boot安全配置忽略允许的端点

时间:2019-12-30 18:23:10

标签: spring spring-boot spring-security jwt

我正在尝试通过JWT获得春季安全性以与应用程序一起使用。我已经阅读了许多教程和示例,但是没有什么适合我的用例。我们不通过用户名/密码进行授权,我们使用twilio来验证手机号码,然后我想创建一个简单的JWT令牌,以手机号码为主题。我已经做到了

这是/ api / v1 / jwt中存在的一个简单端点

@GetMapping("/jwt")
    fun jwt(@RequestParam(value = "number", required = true) number: String): String? {

        val jwtToken = Jwts.builder().setSubject(number).claim("roles", "user").setIssuedAt(Date()).signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString("secret".toByteArray())).compact()

        return jwtToken

    }

返回有效的JWT令牌。

我的安全性配置不再起作用,现在所有端点似乎都受到保护,

@Configuration
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {

    @Bean
    override fun authenticationManagerBean(): AuthenticationManager {
        return super.authenticationManagerBean()
    }

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    }

    override fun configure(http: HttpSecurity) {

        http.csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/api/v1/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)
    }
}

JWT过滤器


    @Throws(IOException::class, ServletException::class)
    override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
        val request = req as HttpServletRequest
        val response = res as HttpServletResponse
        val authHeader = request.getHeader("authorization")
        if ("OPTIONS" == request.method) {
            response.status = HttpServletResponse.SC_OK
            chain.doFilter(req, res)
        } else {
            if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                throw ServletException("Missing or invalid Authorization header")
            }
            val token = authHeader.substring(7)
            try {
                val claims = Jwts.parser().setSigningKey(Base64.getEncoder().encodeToString("secret".toByteArray())).parseClaimsJws(token).body
                request.setAttribute("claims", claims)
            } catch (e: SignatureException) {
                throw ServletException("Invalid token")
            }
            chain.doFilter(req, res)
        }
    }
}

似乎过滤器随时会被命中,而不管其上方的许可情况如何。 不应在任何api / v1 / auth /路径上忽略过滤器吗?我想我错过了一些东西。

第二个问题,有没有一种方法可以应用此过滤器,而不必在之前或之后添加且不扩展https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

编辑:antPathRequestMatcher并未针对configure触发,但是我什至添加了Websecurity configure的路径,我得到了该日志记录

2019-12-30 14:44:44.792 DEBUG 81181 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/auth/request?number=5555555 has an empty filter list```

3 个答案:

答案 0 :(得分:4)

在您的配置中,您具有:

override fun configure(http: HttpSecurity) {
  http.csrf()
  .disable()
  .sessionManagement()
  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  .and()
  .authorizeRequests()
  .antMatchers("/api/v1/auth/**").permitAll()
  .anyRequest().authenticated()
  .and()
  .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)
}

我看到以下内容:

.antMatchers("/api/v1/auth/**").permitAll()
.anyRequest().authenticated()

因此spring security正在检查所有请求的身份验证。 在我的春季配置中,我通常这样做:

.antMatchers("/swagger-ui.html","/webjars/**","/swagger-resources/**", "/v2/**","/csrf")
.permitAll()
.antMatchers("/**")
.authenticated()

因此,请尝试通过设置来更改您的配置:

override fun configure(http: HttpSecurity) {
  http.csrf()
  .disable()
  .sessionManagement()
  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  .and()
  .authorizeRequests()
  .antMatchers("/api/v1/auth/**").permitAll()
  .antMatchers("/**").authenticated()
  .and()
  .addFilterBefore(JwtFilter(), UsernamePasswordAuthenticationFilter::class.java)
}

关于第二个问题:

第二个问题,有没有一种方法可以应用此过滤器而不必 在之前或之后添加且不扩展 https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html

坦白地说,在这种情况下,我将通过使用spring security和spring security oauth sprign security jwt继续使用OAuth / OpenID。

在这种情况下,我将创建一个ResourceServer配置类和一个AuthorizationServer配置类(或者可以将同一类用作AuthorizationServer和ResourceServer)。一个很好的例子在这里https://www.baeldung.com/spring-security-oauth-jwt

我希望它有用

天使

答案 1 :(得分:4)

您可以使用configure(web: WebSecurity),它将绕过spring安全过滤器,并且可以公开访问端点。

override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/api/v1/auth/**",
                "/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**");
    }

您可以使用configure(http: HttpSecurity)进行会话管理和基于角色的身份验证。您可能会看到HttpSecurity vs WebSecurity

对于具有@Component(或任何@Bean风格)的自定义过滤器,WebSecurityConfigurerAdapter会告诉Spring Security忽略通过它添加的任何过滤器。然后,过滤器仍然被调用,因为@Component(或任何形式的@Bean)注释告诉Spring将过滤器(再次)添加到安全链之外。因此,尽管在安全链中忽略了过滤器,但另一个(非安全性?)链并未忽略它。 (See Here

答案 2 :(得分:0)

工作示例

@EnableWebSecurity
class SecurityConfig() : WebSecurityConfigurerAdapter() {

    @Autowired
    lateinit var tokenService: TokenService

    override fun configure(web: WebSecurity) {
        web.ignoring().antMatchers("/v2/api-docs",
                "/configuration/ui",
                "/swagger-resources/**",
                "/configuration/security",
                "/swagger-ui.html",
                "/webjars/**","/api/v1/auth/**");
    }

    override fun configure(http: HttpSecurity) {
        http.cors().and().csrf()
                .disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(JwtFilter(tokenService), UsernamePasswordAuthenticationFilter::class.java)


    }
}