java - Gmail Api 请求的身份验证范围不足

标签 java android google-cloud-platform google-oauth gmail-api

我正在尝试使用 Gmail API 阅读电子邮件,但遇到权限不足问题。

注意:我已设置范围来读取电子邮件。

ManiFestFile.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hatsoff.glogin">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.GLogin">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

我已创建 GoogleSignInOptions 来动态获取电子邮件地址或用户。

  //assign googleAuth
    googleAuth = new GoogleAuth();
    // request for google email
    GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(new Scope(Scopes.DRIVE_APPFOLDER))
            .requestIdToken(getString(R.string.server_client_id))
            .requestServerAuthCode(getString(R.string.server_client_id))
            .requestEmail()
            .build();
    // google_signing object to store gso.
    mGoogleSignInClient = GoogleSignIn.getClient(getApplicationContext(), gso);

当用户从 gsoGoogleSignInOptions 对话框中选择 GoogleAccount 时,将调用此 someActivityResultLauncher。

        //google Dialog click event
    someActivityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {
                @Override
                public void onActivityResult(ActivityResult result) {
                    if (result.getResultCode() == RESULT_OK) {
                        System.out.println("ActivityResult: " + result.getResultCode());
                        Intent data = result.getData();
                        Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
                        authCode = googleAuth.handleSignInResult(task);
                        if (authCode != null) {
                            // Signed in successfully
                            // save AuthCode to sharedPref
                        }
                    } else {
                        System.out.println("ActivityResult: " + result.getResultCode());
                    }
                }
            });

为了获取 AccessToken,我使用 GoogleTokenResponse

ReadEmail 类

    public class ReadMails extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... strings) {
        SharedPreferences AuthCodePre = getSharedPreferences("oAuth", MODE_PRIVATE);
        if (!AuthCodePre.getString("Auth", "").equals("")) {
            try {
                String MailBody = "";
                // Load client secrets.
                AssetManager am = getAssets();
                InputStream in = am.open("credentials.json");
                if (in == null) {
                    throw new FileNotFoundException("Resource not found: " + in);
                }
                GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
                final NetHttpTransport HTTP_TRANSPORT = new com.google.api.client.http.javanet.NetHttpTransport();
                GoogleTokenResponse tokenResponse =
                        new GoogleAuthorizationCodeTokenRequest(
                                HTTP_TRANSPORT,
                                JSON_FACTORY,
                                "https://oauth2.googleapis.com/token",
                                clientSecrets.getDetails().getClientId(),
                                clientSecrets.getDetails().getClientSecret(),
                                AuthCodePre.getString("Auth", ""),
                                "http://localhost")
                                .setScopes(Arrays.asList(SCOPES))
                                .execute();

                String accessToken = tokenResponse.getAccessToken();
                // Use access token to call API
                Credential credential = new GoogleCredential.Builder().setTransport(new com.google.api.client.http.javanet.NetHttpTransport())
                        .setJsonFactory(JSON_FACTORY)
                        .setClientSecrets(clientSecrets.getDetails().getClientId(), clientSecrets.getDetails().getClientSecret())
                        .build()
                        .setAccessToken(accessToken);

                // Build a new authorized API client service.
                Gmail service = new Gmail.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), credential)
                        .setApplicationName(APPLICATION_NAME)
                        .build();
                //Access gmail inbox
                Gmail.Users.Messages.List RequestList = service.users().messages().list(user).setQ("from:<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bfdedddcdbffd8d2ded6d391dcd0d2" rel="noreferrer noopener nofollow">[email protected]</a>");
                ListMessagesResponse listMessagesResponse = RequestList.setMaxResults(100L).execute();
                RequestList.setPageToken(listMessagesResponse.getNextPageToken());

                //Get id of search email
                for (int i = 0; i < listMessagesResponse.getMessages().size(); i++) {
                    String SEmailID = listMessagesResponse.getMessages().get(i).getId();
                    com.google.api.services.gmail.model.Message message = service.users().messages().get(user, SEmailID).execute();
                    //read email body
                    MessagePart msgpart = message.getPayload();
                    List<MessagePart> bodyParts = new ArrayList<>();
                    bodyParts.add(msgpart);
                    for (int j = 0; j < bodyParts.size(); j++) {
                        MailBody = StringUtils.newStringUtf8(Base64.decodeBase64(bodyParts.get(j).getBody().getData()));
                    }
                    System.out.println("EmailBody:==> " + MailBody);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            //signIn
            someActivityResultLauncher.launch(mGoogleSignInClient.getSignInIntent());
        }
        return null;
    }
}

GoogleAuth.java

    public class GoogleAuth {
    public String handleSignInResult(Task<GoogleSignInAccount> completedTask) {
        try {
            GoogleSignInAccount account = completedTask.getResult(ApiException.class);
            System.out.println("ServerAuthCode: " + account.getServerAuthCode());
            return account.getServerAuthCode();
        } catch (ApiException e) {
            System.out.println("getStatusCode: " + e);
            return null;
        }
    }
}

错误日志

W/System.err: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Insufficient Permission",
 W/System.err:     "reason" : "insufficientPermissions"
  } ],
  "message" : "Request had insufficient authentication scopes.",
  "status" : "PERMISSION_DENIED"
}

此行错误:ListMessagesResponse listMessagesResponse = RequestList.setMaxResults(100L).execute();

最佳答案

您已授权您的申请

Scope(Scopes.DRIVE_APPFOLDER)

User.message.list需要以下范围之一

enter image description here

将范围更改为适当的范围并让您的用户重新授权您的应用程序。当用户运行应用程序时,同意屏幕需要显示新范围。

关于java - Gmail Api 请求的身份验证范围不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68842751/

相关文章:

java - 更新后的 Coldfusion 版本 11 中的 Stripe TLS 更新问题

android - Apache Cordova : can't get commons-codec

android - BroadcastReceiver 还是服务?

android - 在android中以编程方式创建 View 时如何传递AttributeSet

node.js - 如何解决GKE容器中的EADDRINUSE问题?

java - Jtextfield 以较小的状态开始

java - 关于这段Java代码的问题,为什么这么写

google-app-engine - App Engine 服务部署停止在已知良好版本上工作

scala - 使用 Scala 和 Dataproc 的云存储客户端 : missing libraries

java - 圆圈会粘在游戏引擎中的东西上