问题
I'm creating a project using SpringBoot2 and VueJS. I'm using a custom JWT token for authorisation. When the user logs in I set a cookie in the response "AUTH_TOKEN=tokenValue". I expected that every call from VueJS (using fetch) would pass that cookie to SpringBoot, but not all endpoints get the cookie.
When I test SpringBoot with RestTemplate and with Postman the cookie is passed just fine and the endpoint works. When I use the VueJS website, the cookie is only passed to endpoints that have "permitAll" in my SecurityConfig.
I have also verified that my VueJS is always sending the cookie (I used a php endpoint to test this and the cookie is always there). So something happens when I use the browser and not all endpoints have the cookie. Here is my Config and how I use it:
Security Config:
@Configuration
open class SecurityConfig(private val jwtTokenProvider :JwtTokenProvider) : WebSecurityConfigurerAdapter() {
@Bean
override fun authenticationManagerBean(): AuthenticationManager {
return super.authenticationManagerBean()
}
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
//@formatter:off
http
.httpBasic().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/thisEndpointDoesGetTheCookie").permitAll()
.anyRequest().authenticated() //Anything else does not
.and()
.apply(JwtConfigurer(jwtTokenProvider))
//@formatter:on
}
}
When I set another endpoint with permitAll then that endpoint starts getting the token too (in my jwtConfigurer/provider)
The call is done using fetch and VueJS
Here is my logout example (same as any other endpoint)
logout() {
fetch('http://localhost:8100/auth/logout', {
method: "post",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
,credentials: 'include', //Yes I'm including the credentials
body: ""
}).then(res => {
console.log("Logout was successful");
}).catch(error => {
console.log(error.message);
console.log("Logout failed");
});
},
This is how I set the cookie when the user logs in. I can see it in the browser
// create a cookie
val cookie = Cookie("AUTH_TOKEN", signedInUser.token)
// expires in 30 days
cookie.maxAge = 30 * 24 * 60 * 60
// optional properties
cookie.secure = authTokenCookieSecure //false for localhost
cookie.isHttpOnly = true
cookie.path = "/"
// add cookie to response
response.addCookie(cookie)
When I make the call using TestRestTemplate (from my tests) or when I'm using postman the endpoints behave as expected.
val headers = HttpHeaders()
headers["Cookie"] = "AUTH_TOKEN=$jwtToken"
What I'm I missing?
回答1:
Problem occurs because you have to configure CORS in Spring Security. For custom headers you have to set your header name in Access-Control-Expose-Headers.
Example solution code:
@Bean
fun corsConfigurationSource(): CorsConfigurationSource {
val configuration = CorsConfiguration().applyPermitDefaultValues()
configuration.allowedOrigins = listOf("*")
configuration.allowedMethods = HttpMethod.values().map { it.name }
configuration.allowedHeaders = listOf("*")
configuration.exposedHeaders = listOf("AUTH_TOKEN")
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", configuration)
return source
}
This CORS configuration allows any domain to access your header. It's good solution for DEV environment. For PROD you should specify origin instead of providing *.
Links: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
来源:https://stackoverflow.com/questions/61752011/springbook-vuejs-springsecurity-cookie-is-not-passed