春季/春季-无法在GET请求中使用JWT

时间:2020-08-20 10:37:17

标签: angular spring-boot rest authentication jwt

我有一个Spring / Boot REST API,该API为会话提供JWT令牌。

我有一个使用2种方法的会话端点,一种用于验证用户身份,一种用于验证Auth令牌。我可以在端点上成功创建和验证令牌(这些令牌上没有过滤器)。一旦尝试使用客户端应用程序访问端点,请求就会爆炸,但是我可以将它们很好地用于像失眠之类的REST客户端。

在JWT令牌上运行的代码在这里:

@Component
public class JwtRequestFilter extends OncePerRequestFilter {


    private final UserService userService;
    private final JwtTokenUtility jwtTokenUtility;

    @Autowired
    public JwtRequestFilter(
            UserService userService,
            JwtTokenUtility jwtTokenUtility
    ) {
        this.userService = userService;
        this.jwtTokenUtility = jwtTokenUtility;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        final String requestTokenHeader = request.getHeader("Authorization"); <-- null

        String username = null;
        String jwtToken = null;
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenUtility.getUsernameFromToken(jwtToken);
            } catch (IllegalArgumentException e) {
                System.out.println("Unable to get JWT Token");
            } catch (ExpiredJwtException e) {
                System.out.println("JWT Token has expired");
            }
        } else {
            logger.warn("JWT Token does not begin with Bearer String"); <-- Therefore, this is called
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = this.userService.loadUserByUsername(username);

            if (jwtTokenUtility.validateToken(jwtToken, userDetails)) {

                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        filterChain.doFilter(request, response);
    }
}

问题在于代码将授权请求标头读取为空,但是当我检查请求标头时,显然它在这里:

Provisional headers are shown
Accept: application/json, text/plain, */*
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJkdWRlY29yMyIsImV4cCI6MTU5NzkzNTQ0NywiaWF0IjoxNTk3OTE3NDQ3fQ.phMnbmkvOW6HKLCnWso-GaX844KMkukS5eADMBko56EEJA-VGgG1qpavwPwHT-tKjxbMuO9VZw3T0rESxQpIqQ
Referer: http://localhost:4200/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36

我的身份验证设置代码如下:


@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    private final UserService userDetailsService;
    private final JwtRequestFilter jwtRequestFilter;

    @Autowired
    public WebSecurityConfig(
            JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
            UserService userDetailsService,
            JwtRequestFilter jwtRequestFilter
    ) {
        super();
        this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
        this.userDetailsService = userDetailsService;
        this.jwtRequestFilter = jwtRequestFilter;
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf()
            .disable()
            .authorizeRequests()
            .antMatchers("/auth", "/auth/validate")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .exceptionHandling()
            .authenticationEntryPoint(this.jwtAuthenticationEntryPoint)
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        httpSecurity.addFilterBefore(this.jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

失败的客户端应用程序是Angular应用程序,从auth返回的JWT令牌存储为cookie,然后拦截器检查cookie,并通过拦截器将值(JWT令牌)附加到请求标头。此方法对我一直有效(如有必要,将提供代码)。下面的屏幕快照显示了完全相同的呼叫已成功返回:

enter image description here

我感觉可能是在受保护的端点上不允许OPTIONS请求,但是我没有证据表明是这种情况。是否可以使用注释或实用程序来接受OPTIONS请求?我在这里做过任何公然错误的事情吗?我很茫然

1 个答案:

答案 0 :(得分:0)

已修复-我刚刚将HTTP配置更新为此:


    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.headers().frameOptions().disable().and().cors().and().csrf().disable();
        httpSecurity.addFilterBefore(this.jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

现在我可以在服务器端接受OPTIONS请求。