对于初学者,我想使用基本身份验证来保护我的rest-api的一部分。 当我尝试从React客户端访问端点时,我在预检请求中总是收到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)
}
}
答案 0 :(得分:0)
我可以通过手动从身份验证中排除预检请求来解决。 添加
antMatchers(OPTIONS, "/**").permitAll()
到authorizeRequests()
配置即可完成。
请注意,Options是对这样导入的HttpMethod枚举值的直接引用
import org.springframework.http.HttpMethod.*
帮助我到达那里的Stackoverflow帖子:
我最初以为,这应该由cors配置处理-显然不是。
答案 1 :(得分:0)
要为单个其余端点启用CORS,您可以使用以下注释它:
int currentPage = 0;
ValueNotifier<int> _changePage = ValueNotifier(currentPage);
// Then in my stateful build I have:
ListView.builder(
controller: _homeController,
itemCount: observations.getCategoryCount(
dictionaryProperties.getSpecificCategory(currentPage)),
itemBuilder: (BuildContext context, int index) {
return CheckboxListTile([...omitted code...);
},
shrinkWrap: true,
physics: ClampingScrollPhysics(),
),
// And on a bottom appBar I have the button to click:
ValueListenableBuilder(
valueListenable: _changePage,
builder: (BuildContext context, int value, Widget child) {
return IconButton(
color: Colors.white,
icon: Icon(Icons.arrow_forward),
onPressed: () {
_homeController.animateTo(
0.0,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 300),
);
setState(() {
currentPage++;
});
},
);
},
),
要允许所有端点使用CORS,您可以使用如下所示的bean:
@CrossOrigin