简体   繁体   English

Firebase服务帐户凭据Json读取权限被拒绝

[英]Firebase Service Account Credentials Json Read permission denied

I downloaded my service account credential json file from Firebase console placed it earlier in the main directory of GAE endpoint project when I run my backed locally it gives Security exception. 我从Firebase控制台下载我的服务帐户凭据json文件时,在本地运行我的服务帐户凭据json文件时,将其更早放置在GAE端点项目的主目录中,它提供了安全性例外。

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

I tried placing the .json file under the src directory also but no help. 我也尝试将.json文件放在src目录下,但没有帮助。

您应该将json文件放在src/main/resources

I found a couple ways to approach this. 我找到了几种解决方法。 First is by getting it from a file over an internet stream. 首先是通过互联网流从文件中获取它。 The other is locally. 另一个在本地。

INTERNET WAY 互联网方式

My first method involved storing the file on my public dropbox folder. 我的第一种方法涉及将文件存储在公共的保管箱文件夹中。 I got the shareable link (make sure it ends in .json ) and pasted it in the string example "https://dl.dropboxusercontent.com/..EXAMPLE-CREDENTIALS" 我得到了可共享的链接(确保它以.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;
    }

LOCAL WAY 本地方式

The other way is taking the version above and skipping something like dropbox 另一种方法是采用上述版本,并跳过类似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;
    }

I don't know if this follows best practice but my project is working now. 我不知道这是否遵循最佳做法,但是我的项目现在正在运行。 I also included firebase's code for getting info. 我还包括用于获取信息的firebase代码。 check out this answer to a question i asked recently on reading and writing to firebase. 查看这个答案,这是我最近在读写Firebase时提出的一个问题

EDIT 编辑

cleaned up version which doesnt throw errors 清理不会抛出错误的版本

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;
    }
}

Finally, I found the solution, Its written under the APIs and references section of Google App Engine in this link , that we need to add such files in the appengine-web.xml file under the <resource-files> tag, using <include path=""/> property. 最后,在此链接中 ,我找到了解决方案(该解决方案写在Google App Engine的API和参考部分下),我们需要使用<include path=""/>将此类文件添加到appengine-web.xml文件中的<resource-files>标记下。 <include path=""/>属性。 After doing so its works for me. 这样做后对我有用。 I placed the .json file containing project credentials in the WEB-INF directory and then entered its relative path in <resource-files> tag. 我将包含项目凭证的.json文件放在WEB-INF目录中,然后在<resource-files>标记中输入其相对路径。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM