Spring Boot REST api 验证 Firebase JWT 令牌

Oir*_*pok 6 spring-security jwt firebase spring-boot firebase-authentication

我有一个 Springboot REST 应用程序,我试图使用 firebase 来保护它,用户身份验证流程如下:

  1. 用户使用 firebase auth 在单独的 Vue 前端进行身份验证,获取 Firebase JWT id 令牌。
  2. 前端将此令牌在 auth 标头中发送到我的后端。
  3. 然后,我的后端应该获取令牌,并通过将令牌发送到 Firebase 服务器进行身份验证。
  4. 如果令牌有效,则返回用户请求的任何资源,而不是返回 401。

我已经配置了前端代码,现在正在通过每个请求发送 JWT 令牌。我正在尝试设置后端,但遇到了一些问题。

我已将 firebase SDK 管理员添加到我的应用程序中,初始化 Firebaseapp,并实现一个 HTTP 过滤器来过滤所有请求以检查和验证令牌。我一直在关注firebase 中有关身份验证令牌的教程。出于某种原因,我的所有请求都返回 403?我不太确定我的实现出了什么问题,因为没有需要修复的错误。

我的 pom xml 片段:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>com.google.firebase</groupId>
    <artifactId>firebase-admin</artifactId>
    <version>7.3.0</version>
</dependency>
<dependency>
    <groupId>com.google.http-client</groupId>
    <artifactId>google-http-client</artifactId>
    <version>1.39.2</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)

我的 firebase 类初始化 firebase SDK:

@Service
public class FirebaseInitialization {
    
    @PostConstruct
    public void initialization() {
        
        try{
            FileInputStream inputStream = new FileInputStream("src/main/resources/serviceAccountKey.json");
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredentials(GoogleCredentials.fromStream(inputStream))
                    .build();

            FirebaseApp.initializeApp(options);
        }
        catch (Exception error) {
            error.printStackTrace();
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

我的安全配置类:

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

    private static final String[] AUTH_WHITELIST = {"/publicEndpoint"};

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().and()
                .csrf().disable()
                .addFilterAfter(new FireBaseTokenFilter(), FireBaseTokenFilter.class)
                .sessionManagement().sessionCreationPolicy(STATELESS).and()
                .authorizeRequests()
                .antMatchers(AUTH_WHITELIST).permitAll()
                .anyRequest().authenticated();

        http.headers().frameOptions().disable();
    }
}
 
Run Code Online (Sandbox Code Playgroud)

我的 HTTP 过滤器检查 firebase 令牌:

public class FireBaseTokenFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String authenticationHeader = request.getHeader("Authorization");

        //checks if token is there
        if (authenticationHeader == null || !authenticationHeader.startsWith("Bearer "))
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,"Missing token!");

        FirebaseToken decodedToken = null;
        try {
            //Extracts token from header
            String token = authenticationHeader.substring(7, authenticationHeader.length());
            //verifies token to firebase server
            decodedToken = FirebaseAuth.getInstance().verifyIdToken(token);
        }
        catch (FirebaseAuthException e) {
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,"Error! "+e.toString());
        }

        //if token is invalid
        if (decodedToken==null){
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED,"Invalid token!");
        }

        chain.doFilter(request,response);
    }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*ski 3

您收到 403 响应,这意味着您的过滤器未运行(过滤器中的所有响应都是 401 响应)。如果你看看你的配置,在这一行:

.addFilterAfter(new FireBaseTokenFilter(), FireBaseTokenFilter.class)你告诉Spring注册一个新的FireBaseTokenFilter,它应该在FireBaseTokenFilter之后调用。这不起作用,因为您还没有注册 FireBase 过滤器。

如果您更改该行,addFilterBefore(new FireBaseTokenFilter(), UsernamePasswordAuthenticationFilter.class)现在将调用过滤器。不过,您仍然需要一种方法来告诉 Spring 用户已通过身份验证。您的过滤器将拒绝使用无效令牌的请求,但我认为它仍然会拒绝使用有效令牌的请求。查看有关Spring 中的 API 安全保护的教程,了解如何配置资源服务器以接受 JWT。

另请注意,FireBase SDK 会验证 ID 令牌,但不会对 FireBase 服务器进行调用。SDK 验证令牌的签名及其内部的一些声明。