Spring boot api给出403禁止错误
Posted
技术标签:
【中文标题】Spring boot api给出403禁止错误【英文标题】:Spring boot api gives 403 forbidden error 【发布时间】:2021-09-04 22:24:56 【问题描述】:我有一个带有 mongo 数据库和 spring security 作为依赖项的 spring boot 应用程序。 它有两个服务,第一个用于身份验证,第二个用于应用程序资源(实体、服务控制器)。 这是我在身份验证服务中的配置类:
@Configuration
@EnableWebSecurity
public class AuthServerSecurityConfig extends WebSecurityConfigurerAdapter
@Override
@Bean
protected UserDetailsService userDetailsService()
return new MongoUserDetailsService();
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.userDetailsService(userDetailsService());
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf().disable()
.authorizeRequests().anyRequest().authenticated();
System.out.println("auth");
@Override
public void configure(WebSecurity web) throws Exception
super.configure(web);
@Bean(name="authenticationManager")
@Lazy
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
这是其余控制器:
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping(value = "/api/users")
public class UserController
@Autowired
UserServiceImpl userServiceImpl;
//Getting all users
@GetMapping(value = "")
public List<UserDTO> getAllUsers()
return userServiceImpl.getAllUsers();
//Getting a user by ID
@GetMapping(value = "/profil/userId")
public UserDTO getUserById(@PathVariable String userId)
return userServiceImpl.getUserById(userId);
//Getting a user by Username
@GetMapping(value = "/profil/username/username")
public UserDTO getUserByUsernameOrEmail(String username)
return userServiceImpl.getUserByUsernameOrEmail(username);
//Logout user and delete token
@PostMapping("/logout")
public void logout(HttpServletRequest request)
userServiceImpl.logout(request);
我将配置方法更改为:
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.authorizeRequests() // authorize
.anyRequest().authenticated() // all requests are authenticated
.and()
.httpBasic();
http.cors();
现在我在访问受保护资源时得到 401 未授权。问题是现在即使我在请求标头中发送正确的不记名令牌,我仍然得到 401 未授权“访问此资源需要完全身份验证”
更新: 我将项目架构从微服务更改为一个简单的 Spring Boot 项目。 这是“AuthServerSecurityConfig”类的新代码
@Configuration
public class AuthServerSecurityConfig extends WebSecurityConfigurerAdapter
@Override
@Bean
protected UserDetailsService userDetailsService()
return new MongoUserDetailsService();
@Autowired
BCryptPasswordEncoder passwordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
//auth.userDetailsService(userDetailsService());
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder);
@Override
protected void configure(HttpSecurity http) throws Exception
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll().and()
.httpBasic();
http.cors();
@Override
public void configure(WebSecurity web) throws Exception
super.configure(web);
@Bean(name="authenticationManager")
@Lazy
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
return super.authenticationManagerBean();
还有这个“ResourceServerConfig”代码:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter
@Autowired private ResourceServerTokenServices tokenServices;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception
resources.resourceId("foo").tokenServices(tokenServices);
@Override
public void configure(HttpSecurity http) throws Exception
http
.authorizeRequests() // authorize
.antMatchers("/oauth/**").permitAll();
http
.authorizeRequests().antMatchers("/api/**").authenticated();
http
.headers().addHeaderWriter(new HeaderWriter()
@Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response)
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getMethod().equals("OPTIONS"))
response.setHeader("Access-Control-Allow-Methods", request.getHeader("Access-Control-Request-Method"));
response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
);
当我尝试访问受保护的资源时,我得到“错误”:“未经授权”, “error_description”:“访问此资源需要完全身份验证”,这是正常行为。问题是现在我无法登录以获取用户 aceess_token。
访问此端点“http://localhost:8080/oauth/token?grant_type=password&username=user&password=user”时,我得到“401 未授权”。
这些是默认的 init 用户凭据,该用户存在于我的 mongodatabase 中,密码格式正确且加密,密码以“$2a”开头,包含“60”个字符。
我进入“编码密码看起来不像 BCrypt 身份验证失败:尝试登录时,控制台中的密码与存储的值不匹配。
【问题讨论】:
你的休息控制器里有什么?有@PreAuthorize
注释吗?
我有一个 @PreAuthorize 注释,但在我试图访问的其余控制器上没有:我更新了我的问题!!
您在哪个端点上得到 403 响应?您是否有可以正常工作的端点?请与调试分享完整的堆栈错误
在“api/users”上。当我删除“.authorizeRequests().anyRequest().authenticated()”时它们工作正常
您是否对这些请求使用经过身份验证的会话?
【参考方案1】:
这是一个使用 jwt 令牌检查配置 spring security 的示例: 您可以将数据源从 h2 更改为 mongodb,并找到我的 repo 中使用的过滤器和提供程序:
https://github.com/e2rabi/sbs-user-management/tree/main/sbs-user-management
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
@FieldDefaults(level = PRIVATE, makeFinal = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
private static final RequestMatcher PUBLIC_URLS = new OrRequestMatcher(
// Put your public API here
new AntPathRequestMatcher("/public/**"),
new AntPathRequestMatcher("/h2-console/**"),
);
private static final RequestMatcher PROTECTED_URLS = new NegatedRequestMatcher(PUBLIC_URLS);
TokenAuthenticationProvider provider;
SecurityConfig(final TokenAuthenticationProvider provider)
super();
this.provider = requireNonNull(provider);
@Override
protected void configure(final AuthenticationManagerBuilder auth)
auth.authenticationProvider(provider);
@Override
public void configure(final WebSecurity web)
web.ignoring().requestMatchers(PUBLIC_URLS);
@Override
protected void configure(final HttpSecurity http) throws Exception
http
.sessionManagement()
.sessionCreationPolicy(STATELESS)
.and()
.exceptionHandling()
// this entry point handles when you request a protected page and you are not yet
// authenticated
.defaultAuthenticationEntryPointFor(forbiddenEntryPoint(), PROTECTED_URLS)
.and()
.authenticationProvider(provider)
.addFilterBefore(restAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
.and()
.csrf().disable()
.cors().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
// h2 console config
http.headers().frameOptions().sameOrigin();
// disable page caching
http.headers().cacheControl();
@Bean
TokenAuthenticationFilter restAuthenticationFilter() throws Exception
final TokenAuthenticationFilter filter = new TokenAuthenticationFilter(PROTECTED_URLS);
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationSuccessHandler(successHandler());
return filter;
@Bean
SimpleUrlAuthenticationSuccessHandler successHandler()
final SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler();
successHandler.setRedirectStrategy(new NoRedirectStrategy());
return successHandler;
@Bean
PasswordEncoder passwordEncoder()
return new BCryptPasswordEncoder();
@Bean
FilterRegistrationBean disableAutoRegistration(final TokenAuthenticationFilter filter)
final FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
@Bean
AuthenticationEntryPoint forbiddenEntryPoint()
return new HttpStatusEntryPoint(FORBIDDEN);
【讨论】:
原来我必须加密密码和客户端密码才能登录并获取令牌 我看到您正在使用 oauth2 授权代码工作流程保护您的 apis 我的解决方案是 jwt 不记名令牌身份验证【参考方案2】:在ResourceServerConfig
类文件中,将configure
方法中的代码更改为以下代码。
http
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll().and()
.httpBasic();
让我知道它是否有效。
【讨论】:
原来我必须加密密码和客户端密码才能登录并获取令牌以上是关于Spring boot api给出403禁止错误的主要内容,如果未能解决你的问题,请参考以下文章
Jquery POST在spring mvc中给出403禁止错误
Yahoo Finance API 在旧 URL 和 User-Agent 上给出错误 403(禁止)
删除操作返回错误:出现意外错误(类型=禁止,状态=403)。禁止的
即使禁用 csrf,Spring security 403 禁止错误也会不断发生