الوصول إلى خدمات البريد باستخدام OAuth
يدعم Aspose.Email for .NET OAuth 2.0، والذي يمكن استخدامه للوصول إلى خوادم SMTP وPOP3 وIMAP وEWS. بشكل عام، أي خادم يدعم رموز حامل OAuth 2.0 يمكن استخدامه مع Aspose.Email، لكن تم اختبار عملاء البريد مع خوادم بريد Google وخوادم Microsoft Office 365.
الوصول إلى خادم من SmtpClient, Pop3Client, ImapClient, و EWSClient مع OAuth يمكن تنفيذها بطريقتين:
- توفير رمز وصول مباشرة إلى منشئ عميل البريد الإلكتروني. في هذه الحالة، يجب أن تضع في اعتبارك أن مدة صلاحية رموز الوصول محدودة. عندما تنتهي صلاحية الرمز، لا يمكن استخدام عميل البريد الإلكتروني للوصول إلى الخادم.
- توفير تنفيذ مخصص لموفر الرمز بناءً على ITokenProvider واجهة إلى منشئ عميل البريد الإلكتروني. في هذه الحالة، يتحقق العميل من وقت انتهاء صلاحية الرمز ويطلب رمز وصول جديد من ITokenProvider عند انتهاء صلاحية الرمز السابق. بهذه الطريقة، يقوم العميل بتجديد الرموز بشكل دوري ويمكنه العمل مع الخادم لمدة غير محدودة. تدعم معظم الخدمات طريقة بسيطة لتجديد رموز الوصول. على سبيل المثال، يمكن استخدام رموز التجديد في خدمات Google، أو تدفق المصادقة ROPC في منصة هوية Microsoft، لتنفيذ موفر رمز.
تكوين حساب على الخادم المناسب
المقالات التالية تساعدك على تكوين الحسابات للوصول إلى خدمات البريد:
- لـ Office 365
- لـ Gmail
الوصول إلى خدمات البريد باستخدام رموز الوصول
تظهر أمثلة الشفرة التالية كيفية الاتصال بخدمات البريد باستخدام رموز الوصول.
// Connecting to SMTP server
using (SmtpClient client = new SmtpClient(
"smtp.gmail.com",
587,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.SSLExplicit))
{
}
// Connecting to IMAP server
using (ImapClient client = new ImapClient(
"imap.gmail.com",
993,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.SSLImplicit))
{
}
// Connecting to POP3 server
using (Pop3Client client = new Pop3Client(
"pop.gmail.com",
995,
"user1@gmail.com",
"accessToken",
true,
SecurityOptions.Auto))
{
}
الوصول إلى خدمات البريد باستخدام موفري الرموز
تُظهر الأمثلة البرمجية التالية كيفية الاتصال بخدمات البريد باستخدام موفر رموز. المدمج TokenProvider.Google المصنع يُستخدم للحصول على موفر يُحدّث رموز الوصول تلقائيًا باستخدام رمز تحديث Google.
ITokenProvider tokenProvider = TokenProvider.Google.GetInstance(
"ClientId",
"ClientSecret",
"RefreshToken");
// Connecting to SMTP server
using (SmtpClient client = new SmtpClient(
"smtp.gmail.com",
587,
"user1@gmail.com",
tokenProvider,
SecurityOptions.SSLExplicit))
{
}
// Connecting to IMAP server
using (ImapClient client = new ImapClient(
"imap.gmail.com",
993,
"user1@gmail.com",
tokenProvider,
SecurityOptions.SSLImplicit))
{
}
// Connecting to POP3 server
using (Pop3Client client = new Pop3Client(
"pop.gmail.com",
995,
"user1@gmail.com",
tokenProvider,
SecurityOptions.Auto))
{
}
تنفيذ ITokenProvider مخصص لـ Office 365
عند عدم توفر موفر رمز مدمج لسيناريوك، يمكنك تنفيذ ITokenProvider الواجهة بنفسك. يوضح المثال أدناه تنفيذ تدفق Credential من نوع Resource Owner Password Credential (ROPC) للحصول على رموز وصول وتحديثها لخدمات بريد Office 365. GetAccessToken الطريقة تخزن الرمز وتطلب رمزًا جديدًا من الخادم فقط عندما ينتهي صلاحية الرمز الحالي.
using JsonConvert = Newtonsoft.Json.JsonConvert;
using Aspose.Email.Clients;
using Aspose.Email.Common.Utils;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Text;
namespace TestNS
{
/// <summary>
/// Azure resource owner password credential (ROPC) token provider
/// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
/// https://portal.azure.com
/// https://developer.microsoft.com/en-us/graph/graph-explorer/#
/// token parser https://jwt.io
/// </summary>
internal class AzureROPCTokenProvider : ITokenProvider
{
private const string uriFormat = "https://login.microsoftonline.com/{0}/oauth2/v2.0/token";
private const string bodyFormat =
"client_id={0}" +
"&scope={1}" +
"&username={2}" +
"&password={3}" +
"&grant_type={4}";
private readonly string scope;
private const string grant_type = "password";
private readonly object tokenSyncObj = new object();
private OAuthToken token;
private readonly string tenant;
private readonly string clientId;
private readonly string clientSecret;
private readonly string userName;
private readonly string password;
/// <summary>
/// Initializes a new instance of the <see cref="AzureROPCTokenProvider"/> class
/// </summary>
public AzureROPCTokenProvider(
string tenant,
string clientId,
string clientSecret,
string userName,
string password,
string[] scopeAr)
{
this.tenant = tenant;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.userName = userName;
this.password = password;
this.scope = string.Join(" ", scopeAr);
}
/// <summary>
/// Gets oAuth access token.
/// </summary>
/// <param name="ignoreExistingToken">
/// If ignoreExistingToken is true, requests a new token from the server. Otherwise the behaviour depends on whether the token exists or not.
/// If the token exists and its expiration date is not expired, returns the current token, otherwise requests a new token from the server.
/// </param>
/// <returns>Returns oAuth access token</returns>
public virtual OAuthToken GetAccessToken(bool ignoreExistingToken)
{
lock (tokenSyncObj)
{
if (this.token != null && !this.token.Expired && !ignoreExistingToken)
return this.token;
token = null;
string uri = string.Format(uriFormat, string.IsNullOrWhiteSpace(tenant) ? "common" : tenant);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
string body = string.Format(bodyFormat,
HttpUtility.UrlEncode(clientId),
HttpUtility.UrlEncode(scope),
HttpUtility.UrlEncode(userName),
HttpUtility.UrlEncode(password),
HttpUtility.UrlEncode(grant_type));
byte[] bytes = Encoding.ASCII.GetBytes(body);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(bytes, 0, bytes.Length);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StringBuilder responseText = new StringBuilder();
bytes = new byte[1024];
int read = 0;
using (Stream stream = response.GetResponseStream())
{
while ((read = stream.Read(bytes, 0, bytes.Length)) > 0)
responseText.Append(Encoding.ASCII.GetString(bytes, 0, read));
}
string jsonString = responseText.ToString();
AzureTokenResponse t = JsonConvert.DeserializeObject<AzureTokenResponse>(jsonString);
token = new OAuthToken(
t.access_token,
TokenType.AccessToken,
DateTime.Now.AddSeconds(t.expires_in));
return token;
}
}
/// <summary>
/// Gets oAuth access token.
/// If the token exists and its expiration date is not expired, returns the current token, otherwise requests a new token from the server.
/// </summary>
/// <returns>Returns oAuth access token</returns>
public OAuthToken GetAccessToken()
{
return GetAccessToken(false);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public virtual void Dispose()
{
}
}
/// <summary>
/// A success response contains a JSON OAuth 2.0 response with the following parameters.
/// </summary>
public class AzureTokenResponse
{
/// <summary>
/// The requested access token. The calling web service can use this token to authenticate to the receiving web service.
/// </summary>
public string access_token { get; set; }
/// <summary>
/// Indicates the token type value. The only type that Azure AD supports is Bearer. For more information about bearer tokens,
/// see The OAuth 2.0 Authorization Framework: Bearer Token Usage (RFC 6750).
/// </summary>
public string token_type { get; set; }
/// <summary>
/// How long the access token is valid (in seconds).
/// </summary>
public int expires_in { get; set; }
/// <summary>
/// How long the access token is valid (in seconds).
/// </summary>
public int ext_expires_in { get; set; }
/// <summary>
/// The time when the access token expires.
/// The date is represented as the number of seconds from 1970-01-01T00:00:00Z UTC until the expiration time.
/// This value is used to determine the lifetime of cached tokens.
/// </summary>
public int expires_on { get; set; }
/// <summary>
/// The App ID URI of the receiving web service.
/// </summary>
public string resource { get; set; }
/// <summary>
/// If an access token was returned, this parameter lists the scopes the access token is valid for.
/// </summary>
public string scope { get; set; }
/// <summary>
/// Issued if the original scope parameter included the openid scope.
/// </summary>
public string id_token { get; set; }
/// <summary>
/// Issued if the original scope parameter included offline_access.
/// </summary>
public string refresh_token { get; set; }
}
}
يوضح المثال البرمجي التالي كيفية الاتصال بخدمات Office 365 باستخدام موفر الرموز المخصص الذي نفذناه أعلاه. يمكن تمرير نفس موفر الرموز إلى عملاء SMTP وIMAP وPOP3 وEWS.
ITokenProvider tokenProvider = new AzureROPCTokenProvider(
"Tenant",
"ClientId",
"ClientSecret",
"EMail",
"Password",
scopes);
// Connecting to SMTP server
using (SmtpClient client = new SmtpClient(
"smtp.office365.com",
587,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.SSLExplicit))
{
}
// Connecting to IMAP server
using (ImapClient client = new ImapClient(
"outlook.office365.com",
993,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.SSLImplicit))
{
}
// Connecting to POP3 server
using (Pop3Client client = new Pop3Client(
"outlook.office365.com",
995,
"Test1@test.onmicrosoft.com",
tokenProvider,
SecurityOptions.Auto))
{
}
// Connecting to EWS server
const string mailboxUri = "https://outlook.office365.com/ews/exchange.asmx";
ICredentials credentials = new OAuthNetworkCredential(tokenProvider);
using (IEWSClient ewsClient = EWSClient.GetEWSClient(mailboxUri, credentials))
{
}