Spring Boot Security 模块在使用来自 React 的 axios 调用时给出 403 错误,但在邮递员中工作正常
Spring Boot Security module gives 403 error when called by using axios from react but works fine in postman
我有一个 spring 引导项目,它使用 spring 安全性和 JWT 令牌。这在 POSTMAN 中工作正常,但在使用 react axios 时会出现 403 错误。
下面是使用的代码
SecurityConfig.java
package com.cg.practice.EmployeeCRUD.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.filter.EmployeeCRUDFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
CustomUserService userService;
@Autowired
EmployeeCRUDFilter employeeCRUDFilter;
/*
* @Autowired CorsFilter corsFilter;
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
System.out.println("Hi1");
auth.userDetailsService(userService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) {
// TODO Auto-generated method stub
System.out.println("Hi2");
try {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
http
// .addFilterBefore(corsFilter, SessionManagementFilter.class)
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
;
http.addFilterBefore(employeeCRUDFilter, UsernamePasswordAuthenticationFilter.class);
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
}
EmployeeCRUDFilter.java
package com.cg.practice.EmployeeCRUD.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.util.JwtUtil;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@Component
public class EmployeeCRUDFilter extends OncePerRequestFilter {
@Autowired
JwtUtil jwtUtil;
@Autowired
CustomUserService userService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
{
// TODO Auto-generated method stub
String authorizationHeader = request.getHeader("Authorization");
String token = null;
String userName = null;
try
{
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
token = authorizationHeader.substring(7);
userName = jwtUtil.extractUsername(token);
}
if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userService.loadUserByUsername(userName);
if (jwtUtil.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
CRUD控制器方法
@PostMapping("/authenticate")
public String generateToken(@RequestBody AuthRequest authRequest) throws Exception
{
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
authRequest.getUserName(),authRequest.getPassword())
);
}
catch (Exception e) {
return "Invalid User/Password";
}
return jwtUtil.generateToken(authRequest.getUserName());
}
反应 Authservice.js
import http from '../Mycomponent/http-common';
class AuthService{
authenticate(){
return http.post("/authenticate", {"userName":"Dip","password":"password@123"}
)
.then(response => {
console.log(response.data)
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
.catch(error =>{
console.log("Error :"+error);
});
}
}
export default new AuthService();
http-common.js
import axios from 'axios';
export default axios.create({
baseURL: "http://localhost:8080/CRUD",
headers: {
"Content-type": "application/json"
}
});
这会在浏览器中产生 403 错误
Failed to load resource: the server responded with a status of 403 ()
AuthService.js:16 Error :Error: Request failed with status code 403
:8080/CRUD/getAll:1 Failed to load resource: the server responded with a status of 403 ()
createError.js:16 Uncaught (in promise) Error: Request failed with status code 403
at createError (createError.js:16:1)
at settle (settle.js:17:1)
at XMLHttpRequest.onloadend (xhr.js:66:1)
谁能帮忙。我坚持了很长时间。我错过了什么吗?我是新来的反应。
在 PostMAN 中工作正常
似乎您在设置 axios 实例时错过了 header 中的 Authorization
我认为问题出在这里:
http
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
您告诉 spring 将 permitAll
请求发送到 /authenticate/
端点,并要求对所有其他请求进行身份验证。但是从前端您正在向 /CRUD/authenticate/
发出请求。这就是您得到 403 的原因,因为此路径必须经过身份验证 - 这意味着请求必须已经具有 Authorization
header。如果将第一行更改为:
,我认为它应该可以工作
.csrf().disable().authorizeRequests().antMatchers("/CRUD/authenticate/")
我有一个 spring 引导项目,它使用 spring 安全性和 JWT 令牌。这在 POSTMAN 中工作正常,但在使用 react axios 时会出现 403 错误。 下面是使用的代码
SecurityConfig.java
package com.cg.practice.EmployeeCRUD.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.filter.EmployeeCRUDFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
CustomUserService userService;
@Autowired
EmployeeCRUDFilter employeeCRUDFilter;
/*
* @Autowired CorsFilter corsFilter;
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// TODO Auto-generated method stub
System.out.println("Hi1");
auth.userDetailsService(userService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) {
// TODO Auto-generated method stub
System.out.println("Hi2");
try {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
corsConfiguration.setAllowedOrigins(List.of("http://localhost:3000"));
corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setExposedHeaders(List.of("Authorization"));
http
// .addFilterBefore(corsFilter, SessionManagementFilter.class)
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
;
http.addFilterBefore(employeeCRUDFilter, UsernamePasswordAuthenticationFilter.class);
}
catch (Exception e)
{
// TODO: handle exception
e.printStackTrace();
}
}
}
EmployeeCRUDFilter.java
package com.cg.practice.EmployeeCRUD.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.cg.practice.EmployeeCRUD.Service.CustomUserService;
import com.cg.practice.EmployeeCRUD.util.JwtUtil;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@Component
public class EmployeeCRUDFilter extends OncePerRequestFilter {
@Autowired
JwtUtil jwtUtil;
@Autowired
CustomUserService userService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
{
// TODO Auto-generated method stub
String authorizationHeader = request.getHeader("Authorization");
String token = null;
String userName = null;
try
{
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
token = authorizationHeader.substring(7);
userName = jwtUtil.extractUsername(token);
}
if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userService.loadUserByUsername(userName);
if (jwtUtil.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
CRUD控制器方法
@PostMapping("/authenticate")
public String generateToken(@RequestBody AuthRequest authRequest) throws Exception
{
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
authRequest.getUserName(),authRequest.getPassword())
);
}
catch (Exception e) {
return "Invalid User/Password";
}
return jwtUtil.generateToken(authRequest.getUserName());
}
反应 Authservice.js
import http from '../Mycomponent/http-common';
class AuthService{
authenticate(){
return http.post("/authenticate", {"userName":"Dip","password":"password@123"}
)
.then(response => {
console.log(response.data)
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
.catch(error =>{
console.log("Error :"+error);
});
}
}
export default new AuthService();
http-common.js
import axios from 'axios';
export default axios.create({
baseURL: "http://localhost:8080/CRUD",
headers: {
"Content-type": "application/json"
}
});
这会在浏览器中产生 403 错误
Failed to load resource: the server responded with a status of 403 ()
AuthService.js:16 Error :Error: Request failed with status code 403
:8080/CRUD/getAll:1 Failed to load resource: the server responded with a status of 403 ()
createError.js:16 Uncaught (in promise) Error: Request failed with status code 403
at createError (createError.js:16:1)
at settle (settle.js:17:1)
at XMLHttpRequest.onloadend (xhr.js:66:1)
谁能帮忙。我坚持了很长时间。我错过了什么吗?我是新来的反应。
在 PostMAN 中工作正常
似乎您在设置 axios 实例时错过了 header 中的 Authorization
我认为问题出在这里:
http
.csrf().disable().authorizeRequests().antMatchers("/authenticate/")
.permitAll().anyRequest().authenticated()
.and().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().cors().configurationSource(request -> corsConfiguration);
您告诉 spring 将 permitAll
请求发送到 /authenticate/
端点,并要求对所有其他请求进行身份验证。但是从前端您正在向 /CRUD/authenticate/
发出请求。这就是您得到 403 的原因,因为此路径必须经过身份验证 - 这意味着请求必须已经具有 Authorization
header。如果将第一行更改为:
.csrf().disable().authorizeRequests().antMatchers("/CRUD/authenticate/")