当前位置: 首页 > 知识库问答 >
问题:

Spring-Security:用CORS预闪获得401(尽管有http.cors())

茹康裕
2023-03-14

对于初学者,我想用基本的身份验证来保护我的一部分Restapi。当我尝试从 react 客户端访问endpoint时,我会在预检请求中不断获取 401。

我试图遵循这个指南,但没有成功:https://www.baeldung.com/spring-security-cors-preflight

我不确定这是否是问题的一部分,但另一部分只能使用某些自定义http标头访问。

我使用方法安全:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = false)
class MethodSecurityConfig : GlobalMethodSecurityConfiguration() {
    override fun customMethodSecurityMetadataSource(): MethodSecurityMetadataSource = SecurityMetadataSource()

    override fun accessDecisionManager(): AccessDecisionManager = super.accessDecisionManager().apply {
        this as AbstractAccessDecisionManager
        decisionVoters.add(PrivilegeVoter())
    }
}

这是我的安全配置:

@Configuration
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
class SecurityConfig : WebSecurityConfigurerAdapter() {
    private val deviceRequestHeaderName: String = "X-DEVICE-ID"    
    private val platformRequestHeaderName: String = "X-PLATFORM-ID"

    @Autowired
    lateinit var users: AppUserRepository

    @Autowired
    lateinit var backendUsers: BackendUserRepository

    @Autowired
    lateinit var roles: RoleRepository

    val authManager by lazy { authenticationManager() }

    private val authProvider by lazy {
        PreAuthenticatedAuthenticationProvider().apply {
            setPreAuthenticatedUserDetailsService {
                val authId = it.principal as UserAuthId
                if (authId.deviceId == null) throw UsernameNotFoundException("No device-id to search for.")
                if (authId.platform == null) throw UsernameNotFoundException("Platform not specified.")
                val platform = try {
                    ApplicationPlatform.valueOf(authId.platform)
                } catch (e: IllegalArgumentException) {
                    throw UsernameNotFoundException("Unknown platform ${authId.platform}.")
                }
                val existingUser = users.findByUserDeviceIdAndPlatform(authId.deviceId, platform)
                if (existingUser != null) return@setPreAuthenticatedUserDetailsService existingUser

                users.save(AppUser(authId.deviceId, platform, roles))
            }
        }
    }

    val passwordEncoder by lazy { BCryptPasswordEncoder() }

    private val deviceIdFilter by lazy {
        HeaderFieldAuthFilter(deviceRequestHeaderName, platformRequestHeaderName).apply {
            setAuthenticationManager(authManager)
        }
    }

    override fun configure(auth: AuthenticationManagerBuilder) = auth {
        authenticationProvider(authProvider)

        val userDetailsService = BackendUserDetailsService(backendUsers)
        userDetailsService(userDetailsService).passwordEncoder(passwordEncoder)
    }

    override fun configure(http: HttpSecurity) = http {
        session {
            sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        }
        exceptionHandling()

        addFilter(deviceIdFilter)
        authorizeRequests().anyRequest().authenticated()
        csrf().disable()
        httpBasic()

        cors().configurationSource { request ->
            CorsConfiguration().apply {
                allowedOrigins = listOf(ALL)
                allowedMethods = listOf(GET, POST, DELETE, PUT, OPTIONS).map { it.name }
                allowedHeaders = listOf(ALL)
                allowCredentials = true
                maxAge = 3600
            }
        }
    }

    @Bean
    fun auditorProvider(): AuditorAware<User> = AuditorAware<User> {
        val authentication = SecurityContextHolder.getContext().authentication
        val user = authentication.run { if (isAuthenticated) principal as? User else null }
        return@AuditorAware Optional.ofNullable(user)
    }
}

共有2个答案

樊杰
2023-03-14

要为单个静止endpoint启用CORS,您可以使用以下方式对其进行注释:

@CrossOrigin

为了允许所有endpoint的CORS,您可以有一个这样的bean:

  @Bean
  public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                .allowedHeaders("*");
      }
    };
麹飞航
2023-03-14

我可以通过手动从身份验证中排除飞行前请求来解决这个问题。加上

antMatchers(OPTIONS, "/**").permitAll()

AuthizeRequest()配置完成了这一点。请注意,Options是对Httpmethod枚举值的直接引用,像这样导入

import org.springframework.http.HttpMethod.*

Stackoverflow帮助我到达那里的帖子:

  • 飞行前响应的HTTP状态代码401无效-Spring
  • 如何在Spring Boot Spring Security应用程序中配置COR

最初,我假设这应该由cors配置处理 - 显然不是。

 类似资料:
  • 我的要求是托管API,并将Function Apps作为后端。我还想要那些API的留档(通过函数应用程序代码自动生成(所以我不必在Api管理上写留档)) 我已经设置了API管理,以便从通过FunctionApp中的URL公开的swagger文件(OpenAPI)导入API。 API看起来不错,我可以在API管理的开发者门户中看到它。但当我真的打电话时,401失败了。 我猜当API管理层发送请求时,

  • 我使用的是Spring Boot2.2.2,作为REST服务发布,并为前端做出反应。 我的Spring应用程序属性: 我的React代码片段: 我也尝试过设置标题,下面是重新修改的控制器。我有多个CORS定义错误。

  • 因此,如果我以角色的身份登录,我就可以很好地访问这个视图。 但是,让我们做一个小的改变,重写一个方法... 这会给我一个...我不明白为什么。 为什么?!! 希望能得到一些帮助来解决这个问题。

  • 问题内容: 我们添加到我们现有的项目中。 从这一刻起,我们从服务器收到401 错误。 这是因为没有标头附加到响应。为了解决这个问题,我们Filter在退出过滤器之前的链中添加了我们自己的过滤器,但是该过滤器不适用于我们的请求。 我们的错误: XMLHttpRequest无法加载。所请求的资源上不存在“ Access-Control-Allow-Origin”标头。http://localhost:

  • 我在一个应用程序中有一个带有Oauth身份验证和资源服务器的Spring启动应用程序。我的前端在一个单独的服务器上,来自一个单独的位置。我的前端应用程序似乎没有将预检操作进行到后端,后端总是以401响应。我的配置如下所示: 请注意,我还必须为静态内容添加例外,因为尽管有任何文档,它似乎无法以其他方式工作。 我试图更明确地指定,但也没有成功: 此时,我无法确定是否遗漏了任何重要的配置,以通过身份验证

  • 我正在尝试配置Spring Security性,使其支持CORS。多亏了这篇文章,Spring security CORS Filter,我已经使用Spring Boot在本地主机上运行了,配置代码如下: } 但是当我在远程Tomcat服务器上部署我的应用程序时,它不起作用: 我的配置类是否足够,还是需要在Tomcat设置中设置一些内容?谢谢你们