request.getheader("授权") 返回 null

问题描述 投票:0回答:1

我正在使用 Spring Boot 应用程序开发一个解耦的 React.js 和 Java,并且刚刚完成了后端的第一部分。诚然,在使用 JWT 方面,我对 Spring Security 并没有牢固的掌握,但我一直在遵循视频教程,并尽我所能阅读文档。不幸的是,该教程有点过时了,我不得不重构其中的某些部分以解决弃用问题。我显然在某个时候犯了一个错误,但无法弄清楚我做错了什么。

当我访问 localhost:8080(后端运行的端口)时,出现 403 错误。这向我表明这是

SecurityConfiguration
的问题,因此我验证了“/”端点位于
permitAll()
行中,确实如此。这是我的全部
SecurityConfiguration
:

package com.keyoflife.keyoflife.config;

import com.keyoflife.keyoflife.services.UserDetailsLoader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfiguration {
    private final UserDetailsLoader usersLoader;
    private final JwtFilter jwtFilter;
    public SecurityConfiguration(UserDetailsLoader usersLoader, JwtFilter jwtFilter) {
        this.usersLoader = usersLoader;
        this.jwtFilter = jwtFilter;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        //TODO: remove this
        //get the hashed version of 'asdfasdf' to save in db
        //System.out.println(new BCryptPasswordEncoder().encode("asdfasdf"));
        return new BCryptPasswordEncoder();
    }
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http, PasswordEncoder passwordEncoder)
            throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.userDetailsService(usersLoader).passwordEncoder(passwordEncoder);
        return authenticationManagerBuilder.build();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .csrf(AbstractHttpConfigurer::disable)
                .cors(Customizer.withDefaults())
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/user-dash").authenticated()
                        .requestMatchers(HttpMethod.OPTIONS,"/api/auth/**", "/login", "/").permitAll()
                )
                .sessionManagement(sess -> sess.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .httpBasic(Customizer.withDefaults())
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
                .formLogin((login) -> login
                        .loginPage("/login")
                        .failureUrl("/login")
                        .defaultSuccessUrl("/user-dash"))
                /* Logout configuration */
                .logout((logout) -> logout
                        .logoutSuccessUrl("/"))
                .build();
    }
    
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOrigin("http://127.0.0.1:8080");
        configuration.setAllowedMethods(Arrays.asList("GET", "POST"));
        configuration.setAllowedHeaders(Arrays.asList("Content-Type", "Authorization"));
        configuration.setAllowCredentials(true); // for cookies. bc everyone likes cookies

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}

接下来,我查看了堆栈跟踪,发现错误实际上发生在我的

JWTFilter
中的
chain.doFilter
行中,在
if()
方法的第一个
doFilterInternal
语句中看到:我将发布这个类和其他类一样似乎无关紧要,因为代码没有通过第一个返回:

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

        // Get authorization header and validate
        final String header = request.getHeader("Authorization");
        System.out.println(header);
        //ensure header has text and starts with "Bearer "
        if (!StringUtils.hasText(header) || (StringUtils.hasText(header) && !header.startsWith("Bearer "))) {
            chain.doFilter(request, response); //Access Denied Exception thrown here because header is null
            return;
        }

//rest of method below

}

我添加了

System.out
行来查看
header
的值是什么,并发现当我尝试访问 localhost8080 时,该值是“Basic(字母数字字符串)”,但是当我尝试访问 / api/auth/login 端点与

{
    "username":"testUser",
    "password": "asdfasdf"
}

使用具有 JSON 正文和 POST 方法的 Postman,我收到 401 错误和 null

header
。我确实验证了这是我数据库中的实际用户。

我看过其他几篇关于这个问题的帖子,并且已经通读了它们。有几篇文章建议添加我拥有的 cors 配置(请参阅

SecurityConfiguration
代码)。另一个说将“授权”arg 添加到我已有的
getHeader
中的
JWTFilter
行。我不知道从这里该去哪里,所以这是我的第一篇 SO 帖子。我已经读了很多年了,但从来没有被困住,以至于我之前需要问一个问题。如果我遗漏了一些相关的内容,我深表歉意。请告诉我,我会编辑我的问题。我只是不想用无关的代码淹没帖子。

java spring-security jwt
1个回答
0
投票

我花了三天时间才弄清楚,但我终于解决了我遇到的问题。事实证明,我没有正确配置 Postman,并且将有效负载发送到了错误的位置。我需要转到 Postman 中的“授权”选项卡并包含我正在使用的密钥,并在同一选项卡上输入有效负载信息。我从下面的 YouTube 视频中得到了答案。

https://www.youtube.com/watch?v=dLxCpd3IGys

如果链接不起作用或者您不想单击链接,请搜索 Postman 的“如何使用 JWT 授权”。

© www.soinside.com 2019 - 2024. All rights reserved.