这是正常行为,因为您使用 admin sdk 凭据向 firestore 发送请求。
您需要在 Spring Boot 应用程序中添加一些身份验证。
我将一些代码放在一起,将您的所有请求置于 firebase 身份验证之后。
FirebaseConfig.java
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix="firebase")
public class FirebaseConfig {
private static final Logger logger = LoggerFactory.getLogger(FirebaseConfig.class);
private String databaseURL;
private String serviceAccount;
@Bean
public DatabaseReference firebaseDatabse() {
DatabaseReference firebase = FirebaseDatabase.getInstance().getReference();
return firebase;
}
@PostConstruct
public void init() {
try {
FirebaseApp.getInstance();
} catch (IllegalStateException e) {
try {
InputStream inputStream = FirebaseConfig.class.getClassLoader().getResourceAsStream(serviceAccount);
try {
FirebaseOptions options = new FirebaseOptions.Builder().setCredentials(GoogleCredentials.fromStream(inputStream))
.setDatabaseUrl(databaseURL).build();
FirebaseApp.initializeApp(options);
} catch (IOException ioE) {
ioE.printStackTrace();
}
} catch (NullPointerException nullE) {
nullE.printStackTrace();
}
}
}
public String getDatabaseURL() {
return databaseURL;
}
public void setDatabaseURL(String databaseURL) {
this.databaseURL = databaseURL;
}
public String getServiceAccount() {
return serviceAccount;
}
public void setServiceAccount(String serviceAccount) {
this.serviceAccount = serviceAccount;
}
}
然后您需要启用网络安全:
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(WebSecurityConfiguration.class);
/**
* Use to create instance of {@link FirebaseAuthenticationTokenFilter}.
*
* @return instance of {@link FirebaseAuthenticationTokenFilter}
*/
public FirebaseAuthenticationTokenFilter firebaseAuthenticationFilterBean() throws Exception {
logger.debug(
"firebaseAuthenticationFilterBean():: creating instance of FirebaseAuthenticationFilter.");
FirebaseAuthenticationTokenFilter authenticationTokenFilter = new FirebaseAuthenticationTokenFilter();
return authenticationTokenFilter;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.and()
.csrf()
.disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Custom security filter
httpSecurity.addFilterBefore(firebaseAuthenticationFilterBean(),
UsernamePasswordAuthenticationFilter.class);
}
}
最后,您添加一个请求过滤器,用于在每次针对 api 发出请求时验证访问令牌。
FirebaseAuthenticationTokenFilter.java
@Component
public class FirebaseAuthenticationTokenFilter extends OncePerRequestFilter {
private static final Logger logger = LoggerFactory.getLogger(FirebaseAuthenticationTokenFilter.class);
private final static String TOKEN_HEADER = "Authorization";
/**
*
* @param request
* @param response
* @param filterChain
* @throws ServletException
* @throws IOException
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
logger.debug("doFilter:: authenticating...");
HttpServletRequest httpRequest = request;
String authToken = httpRequest.getHeader(TOKEN_HEADER);
if (Strings.isNullOrEmpty(authToken)) {
filterChain.doFilter(request, response);
return;
}
try {
Authentication authentication = getAndValidateAuthentication(authToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
logger.debug("doFilter():: successfully authenticated.");
} catch (Exception ex) {
HttpServletResponse httpResponse = response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
logger.debug("Fail to authenticate.", ex);
}
filterChain.doFilter(request, response);
}
/**
*
* @param authToken Firebase access token string
* @return the computed result
* @throws Exception
*/
private Authentication getAndValidateAuthentication(String authToken) throws Exception {
Authentication authentication;
FirebaseToken firebaseToken = authenticateFirebaseToken(authToken);
authentication = new UsernamePasswordAuthenticationToken(firebaseToken, authToken, new ArrayList<>());
return authentication;
}
/**
* @param authToken Firebase access token string
* @return the computed result
* @throws Exception
*/
private FirebaseToken authenticateFirebaseToken(String authToken) throws Exception {
ApiFuture<FirebaseToken> app = FirebaseAuth.getInstance().verifyIdTokenAsync(authToken);
return app.get();
}
@Override
public void destroy() {
logger.debug("destroy():: invoke");
}
}
现在,您的 API 端点将针对未经授权的请求进行保存。
在您的 Web 应用程序中,您可以像平常一样使用 firebase 处理授权。在对 spring-boot 应用程序的每个请求中,您将访问令牌传递为Authorization
header.
请记住,这并不是真正的保存,因为 Spring Boot API 充当 Firebase SDK 的管理员。