【问题标题】:Spring 403 Error - Trying to secure backend with JWT tokensSpring 403 错误 - 尝试使用 JWT 令牌保护后端
【发布时间】:2022-01-10 10:45:45
【问题描述】:

我的所有请求都以 403 Forbidden 响应返回。 我发送的 firebase 令牌已成功验证,所以我不确定我在设置时缺少什么步骤?我只是想获得一个简单的流程,其中我的端点必须在标头中具有有效的 firebase JWT 令牌(在排除的健康端点之外)。

当前步骤:

  1. 已创建自定义 OncePerRequestFilter 并在相应的端点上命中
  2. 授权标头令牌已成功验证
  3. 身份验证对象被创建为 UsernamePasswordAuthenticationToken,在其中跟踪 firebase 令牌和用户 UID。
  4. SecurityContext 使用新的身份验证对象设置。
  5. ????

响应:{ "时间戳": "2022-01-09T16:44:08.342+00:00", “状态”:403, “错误”:“禁止”, "message": "拒绝访问", “路径”:“/v1/dev/overweight/service/user/register” }

被排除在身份验证之外的我的健康端点也能够成功拨打电话。

@EnableWebSecurity
@Configuration
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

    @Value("${server.servlet.context-path:''}")
    private String contextPath;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().and()
                .csrf().disable()
                .addFilterBefore(new FireBaseFilter(), UsernamePasswordAuthenticationFilter.class)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("/health/**").permitAll()
                .anyRequest().authenticated();

    }

    @Override //src: https://www.baeldung.com/spring-cors
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins(
                "http://localhost:8080",
                "http://localhost:3000"
        ).allowedMethods("*");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
 @Slf4j
 public class FireBaseFilter extends OncePerRequestFilter {

    private List<String> skipUrls = Arrays.asList("/health/**");
    private static final String AUTH_HEADER = "Authorization";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authToken = request.getHeader(AUTH_HEADER).substring(7);
        if (!StringUtils.isEmpty(authToken)) {
            Authentication auth = getAuthentication(authToken);
            SecurityContextHolder.getContext().setAuthentication(auth);
        }

        filterChain.doFilter(request, response);
    }

    private Authentication getAuthentication(String jwtToken) {
        FirebaseToken token = verifyFireBaseToken(jwtToken);
        return new UsernamePasswordAuthenticationToken(token.getUid(), token);
    }

  private FirebaseToken verifyFireBaseToken(String jwtToken) {
        if (StringUtils.isEmpty(jwtToken)) {
            throw new IllegalArgumentException("idToken is blank");
        }
        try {
            return FirebaseAuth.getInstance().verifyIdToken(jwtToken, true);
        } catch (FirebaseAuthException e) {
            this.logger.error("exception thrown verifying firebase token");
        }
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        return skipUrls.stream().anyMatch(p -> new AntPathMatcher().match(p, request.getServletPath()));
    }

}

【问题讨论】:

  • 如果您删除 .addFilterBefore(new FireBaseFilter(), UsernamePasswordAuthenticationFilter.class),您并没有写到您的代码正在运行。那么问题是您的自定义过滤器。您未通过身份验证:return new UsernamePasswordAuthenticationToken(token.getUid(), token); 您必须使用其他具有权限的构造器。
  • @dur 嘿,伙计!非常感谢您的帮助,如果我听起来很粗鲁,请道歉。非常感谢您的帮助
  • 我仍然建议您改用 spring security 的内置 jwt 功能并对其进行自定义,而不是编写自定义过滤器。
  • @Toerkumlare 你能给出更多的理由吗?我认为这种方式应该让我更好地控制正在发生的事情,并允许我使用 Firebase SDK 来验证一个令牌,这将阻止对授权服务器的往返 API 调用。此外,我还没有看到不遵循这种设计方法的 Firebase Auth 示例。
  • 为什么?因为编写自定义安全性是不好的做法。 Spring security 提供了 jwt 功能,让你不用自己写。 Spring security jwt 功能经过实战测试,运行 100000 个应用程序,并经过数百个审查。一段错误的代码、一个糟糕的实现以及您的整个应用程序数据都可能受到损害。自定义安全解决方案是不好的做法,使用安全框架的意义何在,由安全框架专家在您不打算使用时编写。

标签: java spring-boot spring-security firebase-authentication jwt


【解决方案1】:

@dur 在 cmets 中解决了。我需要为 UsernamePasswordAuthenticationToken(token.getUid(), token, ); 添加一些权限;

我将方法修改为:

private Authentication getAuthentication(String jwtToken) {
    FirebaseToken token = verifyFireBaseToken(jwtToken);
    this.logger.info("Token verified!");
    List<GrantedAuthority> authoritiesList = new ArrayList<GrantedAuthority>();
    authoritiesList.add(new SimpleGrantedAuthority("ADMIN"));
    return new UsernamePasswordAuthenticationToken(token.getUid(), token, authoritiesList);
}

我认为从这里开始,接下来的步骤将是创建一个适当的 UserDetailsS​​ervice 以正确处理此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-15
    • 1970-01-01
    • 2017-05-13
    • 2018-09-12
    • 2020-07-28
    • 2020-05-07
    • 2021-10-12
    • 2016-11-08
    相关资源
    最近更新 更多