使用 Spring Boot(VueJS 和 Axios 前端)禁止发布 403 帖子
Posted
技术标签:
【中文标题】使用 Spring Boot(VueJS 和 Axios 前端)禁止发布 403 帖子【英文标题】:Getting a Post 403 Forbidden with Spring Boot (VueJS and Axios Frontend) 【发布时间】:2018-02-11 01:31:40 【问题描述】:我在使用 CORS 时遇到了问题,我尝试了 一切 我可以在 Stack Overflow 上找到的所有东西,基本上是我在 Google 上找到的所有东西,但都没有运气。
所以我的后端有用户身份验证,我的前端有一个登录页面。我用 Axios 连接了登录页面,所以我可以发出一个帖子请求并尝试登录,但我一直收到诸如“预检请求”之类的错误,所以我修复了这个问题,然后我开始收到“403 禁止发布”错误。
它看起来像这样:
POST http://localhost:8080/api/v1/login/ 403 (Forbidden)
即使尝试使用 Postman 登录也无法正常工作,因此显然有问题。将在下面发布课程文件
在我的后端,我有一个名为 WebSecurityConfig 的类,它处理所有 CORS 内容:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Bean
public WebMvcConfigurer corsConfigurer()
return new WebMvcConfigurerAdapter()
@Override
public void addCorsMappings(CorsRegistry registry)
registry.addMapping("/**")
.allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS");
;
@Bean
public CorsFilter corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*"); // TODO: lock down before deploying
config.addAllowedHeader("*");
config.addExposedHeader(HttpHeaders.AUTHORIZATION);
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
@Override
protected void configure(HttpSecurity http) throws Exception
http.headers().frameOptions().disable();
http
.cors()
.and()
.csrf().disable().authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/h2/**").permitAll()
.antMatchers(HttpMethod.POST, "/api/v1/login").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/api/v1/login", authenticationManager()),
UsernamePasswordAuthenticationFilter.class);
// And filter other requests to check the presence of JWT in header
//.addFilterBefore(new JWTAuthenticationFilter(),
// UsernamePasswordAuthenticationFilter.class);
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
// Create a default account
auth.userDetailsService(userDetailsService);
// auth.inMemoryAuthentication()
// .withUser("admin")
// .password("password")
// .roles("ADMIN");
在我们用 VueJS 编写并使用 Axios 进行调用的前端上
<script>
import mapActions from 'vuex';
import required, username, minLength from 'vuelidate/lib/validators';
export default
data()
return
form:
username: '',
password: ''
,
e1: true,
response: ''
,
validations:
form:
username:
required
,
password:
required
,
methods:
...mapActions(
setToken: 'setToken',
setUser: 'setUser'
),
login()
this.response = '';
let req =
"username": this.form.username,
"password": this.form.password
;
this.$http.post('/api/v1/login/', req)
.then(response =>
if (response.status === 200)
this.setToken(response.data.token);
this.setUser(response.data.user);
this.$router.push('/dashboard');
else
this.response = response.data.error.message;
, error =>
console.log(error);
this.response = 'Unable to connect to server.';
);
</script>
所以当我通过 Chrome 的工具(网络)进行调试时,我注意到 OPTIONS 请求如下所示:
这是 POST 错误的图片:
这是另一个处理 OPTIONS 请求的类(WebSecurityConfig 中引用的 JWTLoginFilter):
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter
public JWTLoginFilter(String url, AuthenticationManager authManager)
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
@Override
public Authentication attemptAuthentication(
HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException, IOException, ServletException
AccountCredentials creds = new ObjectMapper()
.readValue(req.getInputStream(), AccountCredentials.class);
if (CorsUtils.isPreFlightRequest(req))
res.setStatus(HttpServletResponse.SC_OK);
return null;
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
Collections.emptyList()
)
);
@Override
protected void successfulAuthentication(
HttpServletRequest req,
HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException
TokenAuthenticationService
.addAuthentication(res, auth.getName());
【问题讨论】:
【参考方案1】:我遇到了同样的问题,即 GET 请求正在运行,但 POST 请求被回复为状态 403。
我发现对于我的情况,这是因为默认启用了 CSRF 保护。
确保这种情况的快速方法是禁用 CSRF:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
// …
@Override
protected void configure(HttpSecurity http) throws Exception
// …
http.csrf().disable();
// …
// …
更多信息请访问Spring-Security 网站。
请注意,禁用 CSRF 并不总是正确的答案,因为它是出于安全目的。
【讨论】:
【参考方案2】:您不应该按照 Spring Security 文档禁用 CSRF,除了少数特殊情况。此代码会将 CSRF 标头放入 VUE。我使用了 vue-resource。
//This token is from Thymeleaf JS generation.
var csrftoken = [[$_csrf.token]];
console.log('csrf - ' + csrftoken) ;
Vue.http.headers.common['X-CSRF-TOKEN'] = csrftoken;
希望这会有所帮助。
【讨论】:
【参考方案3】:配置Axios的时候,可以简单的一次性指定header:
import axios from "axios";
const CSRF_TOKEN = document.cookie.match(new RegExp(`XSRF-TOKEN=([^;]+)`))[1];
const instance = axios.create(
headers: "X-XSRF-TOKEN": CSRF_TOKEN
);
export const AXIOS = instance;
然后(这里我假设您使用 SpringBoot 2.0.0,虽然它应该也可以在 SpringBoot 1.4.x 及更高版本中工作)在您的 Spring Boot 应用程序中,您应该添加以下安全配置。
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
// CSRF Token
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// you can chain other configs here
这样,Spring 会在响应中以 cookie 的形式返回令牌(我假设您首先执行 GET
),然后您将在 AXIOS 配置文件中读取它。
【讨论】:
我正在使用 .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 但问题是这仅适用于 GET 操作......为什么它不适用于 PUT、POST 和 DELETE?跨度> 【参考方案4】:默认情况下,Axios 会正确处理 X-XSRF-TOKEN。
所以唯一的操作就是配置服务器,就像 JeanValjean 解释的那样:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Override
protected void configure(HttpSecurity http) throws Exception
http
// CSRF Token
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
// you can chain other configs here
Axios 会自动在请求头中发送正确的令牌,因此无需更改前端。
【讨论】:
以上是关于使用 Spring Boot(VueJS 和 Axios 前端)禁止发布 403 帖子的主要内容,如果未能解决你的问题,请参考以下文章
WebTestClient - 带有 Spring Boot 和 Webflux 的 CORS
Spring-Boot 如何正确注入 javax.validation.Validator
Dockerize vue js前端和spring boot后端并部署在kubernetes集群上