Spring Security不基于用户角色授权请求

km0tfn4u  于 2023-05-07  发布在  Spring
关注(0)|答案(1)|浏览(178)

我正在使用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
1dkrff03

1dkrff031#

已解决

@Document(collection = "app_users")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AppUser {

    @Id
    private ObjectId id;
    @NotBlank(message = "Name is mandatory")
    private String userName;
    @NotBlank(message = "Email is mandatory")
    @Email(message = "Email should be valid")
    private String email;
    @NotBlank(message = "Password is mandatory")
    private String password;

   // @JsonSerialize(using = ToStringSerializer.class)
    @DBRef
    private List<UserRole> roles = new ArrayList<>();

正如有人指出的,我的角色在我的访问令牌中不可见,这使得很难对用户进行身份验证。为了解决这个问题,我在userRole上面添加了@DBRef而不是@DBReference。问题是@DBRef注解表明roles字段引用了单独集合中的另一个文档,而不是将UserRole对象嵌入到文档本身中。

相关问题