我正在使用Sping Boot 和Spring Security构建RESTful API。我已经在WebSecurityConfigurerAdapter中配置了安全过滤器,以允许基于用户角色访问某些端点。然而,当我用不同的用户测试我的端点时,我发现请求没有被正确授权。
下面是我的安全过滤器链的代码:
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AbstractAuthenticationProcessingFilter filter = new CustomAuthenticationFilter(authenticationManager());
filter.setFilterProcessesUrl("/api/v1/login");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeHttpRequests().requestMatchers("/api/v1/login/**","/api/token/refresh/**").permitAll();
http.authorizeHttpRequests().requestMatchers(GET, "/api/v1/user/**").permitAll();
http.authorizeHttpRequests().requestMatchers(GET, "/api/v1/movies/**","/api/v1/reviews").hasAnyAuthority("ROLE_USER");
http.authorizeHttpRequests().requestMatchers(GET, "/api/v1/movies/**","/api/v1/reviews","/api/v1/user").hasAnyAuthority("ROLE_ADMIN");
http.authorizeHttpRequests().requestMatchers(POST,"api/v1/movies/**","/api/v1/reviews/**","api/v1/user/**").hasAuthority("ROLE_ADMIN");
http.authorizeHttpRequests().requestMatchers(PUT,"api/v1/movies/**","/api/v1/reviews/**","api/v1/user/**").hasAuthority("ROLE_ADMIN");
http.authorizeHttpRequests().requestMatchers(DELETE,"api/v1/movies/**","/api/v1/reviews/**","api/v1/user/**").hasAuthority("ROLE_SUPER_ADMIN");
http.authorizeHttpRequests().anyRequest().authenticated();
http.addFilter(filter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
下面是授权过滤器类
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServletPath().equals("/api/v1/login")|| request.getServletPath().equals("/api/v1/token/refresh")) {
filterChain.doFilter(request,response);
}else {
String authorizationHeader= request.getHeader(AUTHORIZATION);
log.info("Authorization header {}",authorizationHeader);
String secretKey = System.getenv("MY_APP_SECRET_KEY");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256(secretKey.getBytes());
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);
String username = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorityCollections = new ArrayList<>();
stream(roles).forEach(role-> {
authorityCollections.add(new SimpleGrantedAuthority(role));
});
UsernamePasswordAuthenticationToken authenticationToken = new
UsernamePasswordAuthenticationToken(username,null
,authorityCollections);
SecurityContextHolder.getContext()
.setAuthentication(authenticationToken);
filterChain.doFilter(request,response);
}catch (JWTVerificationException ex) {
log.info("lets get an exception already");
log.info("Error logging in: {}", ex.getMessage());
response.setHeader("error", ex.getMessage());
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
//response.sendError(HttpServletResponse.SC_FORBIDDEN);
Map<String, String> error = new HashMap<>();
error.put("error_message", ex.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
} else {
log.info("Authorization header: {}", authorizationHeader);
log.info("start do filter");
filterChain.doFilter(request,response);
}
}
}
}
当我向只有具有特定角色的用户才能访问的端点发出请求时,我会收到403 Forbidden响应。我已经确认我正在测试的用户在我的数据库中分配了正确的角色。
编辑
当我打开安全调试日志时,这就是我得到的结果
2023-04-26T17:36:44.776+02:00 INFO 4348 --- [nio-8080-exec-3] d.b.m.filter.CustomAuthorizationFilter : Authorization header Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhcm5vbGRAZ21haWwuY29tIiwiZXhwIjoxNjgyNTI0Mjc0LCJpc3MiOiIvYXBpL3YxL2xvZ2luIiwicm9sZXMiOltdfQ._11bP_6XwvOX1upcRM8WhvXf6KdQQSMrlW3405VgjBM
2023-04-26T17:36:44.847+02:00 DEBUG 4348 --- [nio-8080-exec-3] o.s.s.w.access.AccessDeniedHandlerImpl : Responding with 403 status code
2023-04-26T17:36:44.852+02:00 DEBUG 4348 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : Securing GET /error
2023-04-26T17:36:44.860+02:00 DEBUG 4348 --- [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
2023-04-26T17:36:44.861+02:00 DEBUG 4348 --- [nio-8080-exec-3] o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
1条答案
按热度按时间1dkrff031#
已解决
正如有人指出的,我的角色在我的访问令牌中不可见,这使得很难对用户进行身份验证。为了解决这个问题,我在userRole上面添加了@DBRef而不是@DBReference。问题是@DBRef注解表明roles字段引用了单独集合中的另一个文档,而不是将UserRole对象嵌入到文档本身中。