Firebase 服务账户凭据 JSON 读取权限被拒绝。

5

我从Firebase控制台下载了服务账号凭证的json文件,将其放置在GAE端点项目的主目录中。然后,在本地运行后端时,出现了安全异常。

java.security.AccessControlException: access denied ("java.io.FilePermission" "\src\main\secret.json" "read")

我尝试将.json文件放在src目录下,但没有帮助。

我现在遇到了完全相同的问题。我尝试将它放在我的驱动器中,并像这样访问:.setServiceAccount(new URL("https://drive.google.com/file/...").openStream()),但是我被拒绝访问,尽管没有任何权限阻止它。我很乐意看看其他人想出什么解决方法。 - booky99
我今晚会发布我找到的解决方案。我有几个解决方法可以提供给你。请给我大约2个小时的时间。 - booky99
3个回答

0

你应该将json文件放置在src/main/resources目录下


0

最终,我找到了解决方案。在Google App Engine的API和参考文档部分link中写明,我们需要在appengine-web.xml文件的<resource-files>标签下添加这些文件,使用<include path=""/>属性。这样做后,它对我有效。我将包含项目凭据的.json文件放置在WEB-INF目录中,然后在<resource-files>标签中输入其相对路径。


你的相对路径是什么样子?即使将其添加到resource-files标签后,我仍然遇到了这个错误。也许与路径有关?另外,在初始化Firebase时是否有任何不同之处?例如,引用文件的路径看起来如何?谢谢。 - Daniel George

0

我找到了几种方法来解决这个问题。第一种是通过从互联网流中获取文件。另一种是本地方式。

互联网方式

我的第一种方法涉及将文件存储在我的公共Dropbox文件夹中。我获取了可共享的链接(确保以.json结尾),并将其粘贴到字符串示例"https://dl.dropboxusercontent.com/..EXAMPLE-CREDENTIALS"中。

/** A simple endpoint method that takes a name and says Hi back */
    @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {

        MyBean mModelClassObject = null;

        String text = "";

        try {
            String line = "";
            StringBuilder builder = new StringBuilder();
            URL url = new URL("https://dl.dropboxusercontent.com/..EXAMPLE-CREDENTIALS");
            BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));


            while ((line = reader.readLine()) != null) {
                // ...
                builder.append(line);
            }
            reader.close();

            text = builder.toString();
        } catch (MalformedURLException e) {
            // ...
        } catch (IOException e) {
            // ...
        }

        InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));

        FirebaseOptions options = null;
        options = new FirebaseOptions.Builder()
                .setServiceAccount(stream)
                .setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
                .build();
        FirebaseApp.initializeApp(options);

        DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
        final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();


        Task<MyBean> tcsTask = tcs.getTask();

        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                MyBean result = dataSnapshot.getValue(MyBean.class);
                if(result != null){
                    tcs.setResult(result);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError){
                //handle error
            }
        });

        try {
            mModelClassObject = Tasks.await(tcsTask);
        }catch(ExecutionException e){
            //handle exception
        }catch (InterruptedException e){
            //handle exception
        }

        return mModelClassObject;
    }

本地方式

另一种方法是使用上面的版本,跳过像Dropbox这样的东西。

/** A simple endpoint method that takes a name and says Hi back */
        @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {

        MyBean mModelClassObject = null;

        String text = "JUST PASTE YOUR JSON CONTENTS HERE";

        InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));

        FirebaseOptions options = null;
        options = new FirebaseOptions.Builder()
                .setServiceAccount(stream)
                .setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
                .build();
        FirebaseApp.initializeApp(options);

        DatabaseReference ref = FirebaseDatabase.getInstance().getReference();
        final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();


        Task<MyBean> tcsTask = tcs.getTask();

        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                MyBean result = dataSnapshot.getValue(MyBean.class);
                if(result != null){
                    tcs.setResult(result);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError){
                //handle error
            }
        });

        try {
            mModelClassObject = Tasks.await(tcsTask);
        }catch(ExecutionException e){
            //handle exception
        }catch (InterruptedException e){
            //handle exception
        }

        return mModelClassObject;
    }

我不确定这是否符合最佳实践,但我的项目现在正在运行。我还包括了Firebase获取信息的代码。请查看我最近在读写Firebase方面提出的问题的答案。

编辑

已清理版本,不会抛出错误。

public class MyEndpoint {

    private FirebaseOptions options;
    private DatabaseReference ref;
    private String serviceAccountJSON = "i took mine out for security reasons";

    // create firebase instance if need be
    private void connectToFirebase(){
        if (options == null) {
            options = null;
            options = new FirebaseOptions.Builder()
                    .setServiceAccount(new ByteArrayInputStream(serviceAccountJSON.getBytes(StandardCharsets.UTF_8)))
                    .setDatabaseUrl("https://[PROJECT-ID].firebaseio.com/")
                    .build();
            FirebaseApp.initializeApp(options);
        }
        if(ref == null) {
            ref = FirebaseDatabase.getInstance().getReference();
        }
    }

    /** A simple endpoint method that takes a name and says Hi back */
    @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {

        // always do this first
        connectToFirebase();

        MyBean mModelClassObject = null;

        final TaskCompletionSource<MyBean> tcs = new TaskCompletionSource<>();
        Task<MyBean> tcsTask = tcs.getTask();

        // get the info
        ref.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                MyBean result = dataSnapshot.getValue(MyBean.class);
                if(result != null){
                    tcs.setResult(result);
                }
            }

            @Override
            public void onCancelled(DatabaseError databaseError){
                //handle error
            }
        });

        // wait for it
        try {
            mModelClassObject = Tasks.await(tcsTask);
        }catch(ExecutionException e){
            //handle exception
        }catch (InterruptedException e){
            //handle exception
        }

        mModelClassObject.setData(mModelClassObject.getData() + name);

        return mModelClassObject;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接