在 MailKit 中使用 GMail OAuth2.0 进行身份验证的正确方法是什么?
What is the correct way to authenticate using GMail OAuth2.0 in MailKit?
我正在尝试使用 Mailkit 从我的 Gmail 中获取电子邮件:
private readonly string[] Scopes = { GmailService.Scope.GmailReadonly };
private UserCredential GetGmailCredential()
{
UserCredential credential;
using (var stream = new FileStream("client_id.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true),
new LocalServerCodeReceiver()).Result;
Console.WriteLine($"Credential file saved to: {credPath}");
}
return credential;
}
[HttpGet("check")]
public string GetD()
{
using (var client = new ImapClient())
{
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
UserCredential credential = GetGmailCredential();
//var oauth2 = new SaslMechanismOAuth2("myaccount008@gmail.com", credential.Token.AccessToken);
var oauth2 = new SaslMechanismOAuth2("myaccount008",credential.Token.AccessToken);
client.Authenticate(oauth2);
client.Inbox.Open(FolderAccess.ReadOnly);
var uids = client.Inbox.Search(SearchQuery.FromContains("bill"));
string subjects = string.Empty;
foreach (var uid in uids)
{
var message = client.Inbox.GetMessage(uid);
subjects += message.Subject + Environment.NewLine;
// write the message to a file
message.WriteTo(string.Format("{0}.eml", uid));
}
client.Disconnect(true);
return subjects;
}
}
Line: client.Authenticate(oauth2);
throw exception ->
MailKit.Security.AuthenticationException
我按照这个 answer 设置了我的 Gmail API,但后来我遇到了身份验证失败的问题。
更新 1
这是日志:
已连接到 imaps://imap.gmail.com:993/ S: * OK Gimap 准备就绪
来自 122.199.45.135 d3mb920463124pjs C: A00000000 的请求
S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST
儿童 X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN
AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH S: A00000000 OK
这就是她写的全部! d3mb920463124pjs C: A00000001 验证
XOAUTH2
dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpcLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FOTmhEYk5rAQE=
小号:+
eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoPQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
C: S: A00000001 NO [AUTHENTICATIONFAILED] 无效凭据
(失败)
作用域,我用:GmailService.Scope.GmailReadonly
因为我只需要检索电子邮件。
更新 2
将我的范围更新为:
private readonly string[] Scopes = { GmailService.Scope.MailGoogleCom };
连接到imaps://imap.gmail.com:993/
S: * OK Gimap 准备好接受来自 122.199.45.135 s90mb321411106pjc 的请求
C:A00000000 能力。
S: * CAPABILITY IMAP4rev1 取消选择空闲命名空间配额 ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH
S: A00000000 OK 这就是她写的全部! s90mb321411106pjc
C: A00000001 AUTHENTICATE XOAUTH2 dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpXLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FPTmhEYk5rAQE=
小号:+
eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiSmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
C:
S: A00000001 NO [AUTHENTICATIONFAILED] 无效凭证(失败)
更新 3
我保持一切不变,也尝试使用 GmailService.Scope.ReadOnly
然后将 ImapClient 替换为以下代码,现在可以使用了。
// Create Gmail API service.
service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
这段代码来自GmailApi。如果能用Mailkit做认证就好了
部分问题是您使用了错误的范围。您需要使用 GoogleService.Scope.MailGoogleCom.
您使用的范围不适用于 IMAP 或 POP3 访问,它仅适用于 Google 的网络请求 API。
以下代码适用于我:
const string GMailAccount = "username@gmail.com";
var clientSecrets = new ClientSecrets {
ClientId = "XXX.apps.googleusercontent.com",
ClientSecret = "XXX"
};
var codeFlow = new GoogleAuthorizationCodeFlow (new GoogleAuthorizationCodeFlow.Initializer {
DataStore = new FileDataStore ("CredentialCacheFolder", false),
Scopes = new [] { "https://mail.google.com/" },
ClientSecrets = clientSecrets
});
var codeReceiver = new LocalServerCodeReceiver ();
var authCode = new AuthorizationCodeInstalledApp (codeFlow, codeReceiver);
var credential = await authCode.AuthorizeAsync (GMailAccount, CancellationToken.None);
if (authCode.ShouldRequestAuthorizationCode (credential.Token))
await credential.RefreshTokenAsync (CancellationToken.None);
var oauth2 = new SaslMechanismOAuth2 (credential.UserId, credential.Token.AccessToken);
using (var client = new ImapClient ()) {
await client.ConnectAsync ("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}
我正在尝试使用 Mailkit 从我的 Gmail 中获取电子邮件:
private readonly string[] Scopes = { GmailService.Scope.GmailReadonly };
private UserCredential GetGmailCredential()
{
UserCredential credential;
using (var stream = new FileStream("client_id.json", FileMode.Open, FileAccess.Read))
{
// The file token.json stores the user's access and refresh tokens, and is created
// automatically when the authorization flow completes for the first time.
string credPath = "token.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true),
new LocalServerCodeReceiver()).Result;
Console.WriteLine($"Credential file saved to: {credPath}");
}
return credential;
}
[HttpGet("check")]
public string GetD()
{
using (var client = new ImapClient())
{
client.Connect("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
UserCredential credential = GetGmailCredential();
//var oauth2 = new SaslMechanismOAuth2("myaccount008@gmail.com", credential.Token.AccessToken);
var oauth2 = new SaslMechanismOAuth2("myaccount008",credential.Token.AccessToken);
client.Authenticate(oauth2);
client.Inbox.Open(FolderAccess.ReadOnly);
var uids = client.Inbox.Search(SearchQuery.FromContains("bill"));
string subjects = string.Empty;
foreach (var uid in uids)
{
var message = client.Inbox.GetMessage(uid);
subjects += message.Subject + Environment.NewLine;
// write the message to a file
message.WriteTo(string.Format("{0}.eml", uid));
}
client.Disconnect(true);
return subjects;
}
}
Line: client.Authenticate(oauth2); throw exception ->
MailKit.Security.AuthenticationException
我按照这个 answer 设置了我的 Gmail API,但后来我遇到了身份验证失败的问题。
更新 1
这是日志:
已连接到 imaps://imap.gmail.com:993/ S: * OK Gimap 准备就绪 来自 122.199.45.135 d3mb920463124pjs C: A00000000 的请求 S: * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST 儿童 X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH S: A00000000 OK 这就是她写的全部! d3mb920463124pjs C: A00000001 验证 XOAUTH2 dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpcLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FOTmhEYk5rAQE= 小号:+ eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoPQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ== C: S: A00000001 NO [AUTHENTICATIONFAILED] 无效凭据 (失败)
作用域,我用:GmailService.Scope.GmailReadonly 因为我只需要检索电子邮件。
更新 2
将我的范围更新为:
private readonly string[] Scopes = { GmailService.Scope.MailGoogleCom };
连接到imaps://imap.gmail.com:993/ S: * OK Gimap 准备好接受来自 122.199.45.135 s90mb321411106pjc 的请求 C:A00000000 能力。 S: * CAPABILITY IMAP4rev1 取消选择空闲命名空间配额 ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH2 AUTH=PLAIN AUTH=PLAIN-CLIENTTOKEN AUTH=OAUTHBEARER AUTH=XOAUTH S: A00000000 OK 这就是她写的全部! s90mb321411106pjc C: A00000001 AUTHENTICATE XOAUTH2 dXNlcj1mcmFudmEwMDhAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuYTBBZHcxeGVWZDNSWWwzcVZlblZwVm1MbDBRRVVyWkdxd05veEd0QWpXLVhHNjRBaF90eWM0NWhwSFprZHA0d3dPWlpGMVZwbGM3dGo1Tm80eVMwc2lPNE1VYmhHV1I1WE9sdWtLUGY4TF9QU0dpZjhrSWM2UXNUbTQwYjlweDNBeXE4bVYtOTM2akEtSHdXekNQVFdGMGk0NGozX2FPTmhEYk5rAQE= 小号:+ eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiSmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ== C: S: A00000001 NO [AUTHENTICATIONFAILED] 无效凭证(失败)
更新 3
我保持一切不变,也尝试使用 GmailService.Scope.ReadOnly 然后将 ImapClient 替换为以下代码,现在可以使用了。
// Create Gmail API service.
service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
这段代码来自GmailApi。如果能用Mailkit做认证就好了
部分问题是您使用了错误的范围。您需要使用 GoogleService.Scope.MailGoogleCom.
您使用的范围不适用于 IMAP 或 POP3 访问,它仅适用于 Google 的网络请求 API。
以下代码适用于我:
const string GMailAccount = "username@gmail.com";
var clientSecrets = new ClientSecrets {
ClientId = "XXX.apps.googleusercontent.com",
ClientSecret = "XXX"
};
var codeFlow = new GoogleAuthorizationCodeFlow (new GoogleAuthorizationCodeFlow.Initializer {
DataStore = new FileDataStore ("CredentialCacheFolder", false),
Scopes = new [] { "https://mail.google.com/" },
ClientSecrets = clientSecrets
});
var codeReceiver = new LocalServerCodeReceiver ();
var authCode = new AuthorizationCodeInstalledApp (codeFlow, codeReceiver);
var credential = await authCode.AuthorizeAsync (GMailAccount, CancellationToken.None);
if (authCode.ShouldRequestAuthorizationCode (credential.Token))
await credential.RefreshTokenAsync (CancellationToken.None);
var oauth2 = new SaslMechanismOAuth2 (credential.UserId, credential.Token.AccessToken);
using (var client = new ImapClient ()) {
await client.ConnectAsync ("imap.gmail.com", 993, SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync (oauth2);
await client.DisconnectAsync (true);
}