1

目前正在执行从 Spring Boot v2.3.5 到 v2.4.0 的升级。但是,当用户通过身份验证并实际通过FilterChain时,我遇到了设置SecurityContextHolder的问题。

有问题的代码是扩展BasicAuthenticationFilter的类的一部分,如下所示:

    /**
     * Perform the filter for authentication
     *
     * @param request  The HttpServletRequest
     * @param response The HttpServletResponse
     * @param chain    The FilterChain
     * @throws IOException      When the filter could not be performed
     * @throws ServletException When the filter could not be performed
     */
    @Override
    protected void doFilterInternal(final HttpServletRequest request,
                                    final HttpServletResponse response,
                                    final FilterChain chain) throws IOException, ServletException {
        final String header = request.getHeader(jwtConfiguration.getHeader());

        if (header == null || !header.startsWith(jwtConfiguration.getTokenPrefix())) {
            chain.doFilter(request, response);
            return;
        }

        final UsernamePasswordAuthenticationToken authentication = getAuthentication(request);

        if (authentication == null) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        } else {
            final SecurityContext context = SecurityContextHolder.createEmptyContext();

            context.setAuthentication(authentication);
            SecurityContextHolder.setContext(context);

            chain.doFilter(request, response); // The exception is thrown here, but only when setting the SecurityContextHolder
        }
    }


...

    /**
     * Get the UsernamePasswordAuthenticationToken from the HttpServletRequest
     *
     * @param request The HttpServletRequest
     * @return The UsernamePasswordAuthenticationToken that was filtered from the HttpServletRequest
     */
    private UsernamePasswordAuthenticationToken getAuthentication(final HttpServletRequest request) {
        final String token = request.getHeader(jwtConfiguration.getHeader());
        if (token != null && !token.isEmpty()) {
            final UserDto user = authorizationService.getCurrentUser(token);

            if (user != null) {
                final Set<GrantedAuthority> grantedAuthorities = new HashSet<>();

                if (user.getRoles() != null) {
                    for (final RoleDto role : user.getRoles()) {
                        if (role.getPermissions() != null) {
                            for (final PermissionDto permission : role.getPermissions()) {
                                grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
                            }
                        }
                    }
                }

                return new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
            }
            return null;
        }
        return null;
    }

如果不设置SecurityContextHolder,代码就可以正常工作,但不幸的是,不会设置身份验证,这不是我想要的结果,因为我想保护某些端点。

扩展WebSecurityConfigurerAdapter的类设置如下:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final JwtConfiguration jwtConfiguration;
    private final IAuthorizationService userService;

    /**
     * Initialize a new WebSecurityConfiguration
     *
     * @param jwtConfiguration The JwtConfiguration object
     * @param userService      The IAuthorizationService implementation
     */
    public WebSecurityConfiguration(@Autowired final JwtConfiguration jwtConfiguration,
                                    @Autowired final IAuthorizationService userService) {
        if (jwtConfiguration == null)
            throw new NullPointerException("JwtConfig cannot be null!");
        if (userService == null)
            throw new NullPointerException("IAuthorizationService cannot be null!");

        this.jwtConfiguration = jwtConfiguration;
        this.userService = userService;
    }

    /**
     * Configure the HttpSecurity
     *
     * @param http The HttpSecurity object
     * @throws Exception When the configuration failed
     */
    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        final AuthenticationManager authenticationManager = authenticationManager();

        http
                .csrf().disable().cors().and()
                .authorizeRequests()
                .antMatchers("/authentication/**",
                        "/v2/api-docs",
                        "/configuration/ui",
                        "/swagger-resources/**",
                        "/configuration/security",
                        "/swagger-ui.html",
                        "/webjars/**")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(new JwtAuthorizationFilter(authenticationManager, jwtConfiguration, userService), JwtAuthorizationFilter.class)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

在通过链时设置 SecurityContextHolder 时发生的异常本身如下:

java.lang.IllegalStateException:没有找到接口 org.springframework.security.core.Authentication 的主要或单个公共构造函数 - 也没有找到默认构造函数

异常堆栈跟踪

4

0 回答 0