使用Oauth2的EWS java API
我想对我的应用程序使用Oauth2身份验证。我想使用EWS Java API从O365获取数据。可能吗? 文件 关于获取RESTAPI的oauth令牌的讨论我是否也应该使用相同的文档来获取用于EWS web服务的令牌?使用Oauth2的EWS java API,java,oauth,ms-office,exchangewebservices,Java,Oauth,Ms Office,Exchangewebservices,我想对我的应用程序使用Oauth2身份验证。我想使用EWS Java API从O365获取数据。可能吗? 文件 关于获取RESTAPI的oauth令牌的讨论我是否也应该使用相同的文档来获取用于EWS web服务的令牌? 任何人都可以与java共享任何这样做的代码示例。这是可能的。您必须以与REST相同的方式注册应用程序,但需要指定特殊的EWS权限“通过EWS完全访问用户邮箱”。您需要执行OAuth流来检索访问令牌,然后将其包含在EWS请求的授权头中。我没有Java示例,但这些是所需的基本步骤。我
任何人都可以与java共享任何这样做的代码示例。这是可能的。您必须以与REST相同的方式注册应用程序,但需要指定特殊的EWS权限“通过EWS完全访问用户邮箱”。您需要执行OAuth流来检索访问令牌,然后将其包含在EWS请求的授权头中。我没有Java示例,但这些是所需的基本步骤。我知道,这个问题已经很老了,但答案和注释今天仍然对我有帮助。所以,我想简单总结一下: 在该请求中: 标题验证已删除,如接受答案注释中所述 因此,通过设置令牌就足够了
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.getHttpHeaders().put("Authorization", "Bearer " + officeToken);
不要设置任何其他凭据
为了完整性:在我的场景中,officeToken
通过officejavascript api在客户端检索
Office.initialize = function() {
$(document).ready(function (){
Office.context.mailbox.getCallbackTokenAsync(function(result) {
result.value; // is the officeToken of above
// do s.th. with the officeToken; e.g. send it to the server
});
});
});
在服务器上,我们现在可以获取邮件的内容。在最新版本的Office JavaScript Api中,这也可以直接在客户端中实现。但是,您的Exchange Api版本必须为1.3。因此,如果您的Exchange服务器运行的是旧版本,此解决方案(检索令牌并将其发送到服务器)非常有用。鉴于将基本身份验证与EWS结合使用将在2020年10月()停止工作,我决定让我的应用程序改为使用OAuth令牌身份验证 正如Jason Johnson所提到的,您需要允许Azure广告应用程序通过EWS完全访问用户邮箱。您可以想象,这会造成安全问题,因为应用程序可以访问和修改该租户中的任何人邮箱。小心使用 免责声明-不再支持adal4j,尽管此解决方案有效,但请注意adal4j库存在一个错误,该错误将被错误地修复 在
AdalCallable.java
中记录错误。这会修补问题,但不会公开
工件是可用的,所以您需要自己编译它。另一个选择可能是尝试更多
但是,我还没有用它测试这个解决方案
图书馆
以下是我使用的maven依赖项,我排除了slf4j,因为我在glassfish中遇到了类装入器冲突,所以排除是可选的:
<dependency>
<groupId>com.microsoft.ews-java-api</groupId>
<artifactId>ews-java-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
<version>1.6.4</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
com.microsoft.ews-java-api
ews java api
2
com.microsoft.azure
adal4j
1.6.4
org.slf4j
slf4j api
org.slf4j
slf4j api
1.7.21
测试
以下是令牌提供程序:
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.enterprise.concurrent.ManagedExecutorService;
import org.apache.log4j.Logger;
import com.microsoft.aad.adal4j.AuthenticationCallback;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.WebProxy;
import microsoft.exchange.webservices.data.core.enumeration.misc.ConnectingIdType;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.misc.ImpersonatedUserId;
/**
* Used to obtain an access token for use in an EWS application. Caches the
* token and refreshes it 5mins prior to expiration.
*
* @author Stephen O'Hair
*
*/
public final class MsEwsTokenProvider {
private static final Logger log = Logger.getLogger(MsEwsTokenProvider.class);
private static final String EWS_URL = "https://outlook.office365.com/EWS/Exchange.asmx";
private static final String RESOUCE = "https://outlook.office365.com";
private static final String TENANT_NAME = "enter your tenant name here";
private static final String AUTHORITY = "https://login.microsoftonline.com/" + TENANT_NAME;
private static final long REFRESH_BEFORE_EXPIRY_MS = Duration.ofMinutes(5).toMillis();
private static long expiryTimeMs;
private static String accessToken;
/**
* Takes an OAuth2 token and configures an {@link ExchangeService}.
*
* @param token
* @param senderAddr
* @param traceListener
* @param mailboxAddr
* @return a configured and authenticated {@link ExchangeService}
* @throws URISyntaxException
* @throws Exception
*/
public static ExchangeService getAuthenticatedService(String token, String senderAddr,
TraceListener traceListener) throws URISyntaxException, Exception {
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
service.setTraceListener(traceListener);
service.getHttpHeaders().put("Authorization", "Bearer " + token);
service.getHttpHeaders().put("X-AnchorMailbox", senderAddr);
//service.setWebProxy(new WebProxy(proxyHost, proxyPort));
service.setUrl(new URI(EWS_URL));
service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.PrincipalName, senderAddr));
return service;
}
/**
* Simple way to get an access token using the Azure Active Directory Library.
*
* Authenticates at : https://login.microsoftonline.com/
*
* @param clientId
* - client id of the AzureAD application
* @param clientSecret
* - client secret of the AzureAD application
* @param service
* - managed executor service
*
* @return provisioned access token
* @throws MalformedURLException
* @throws InterruptedException
* @throws ExecutionException
* @throws TimeoutException
*/
public static synchronized String getAccesToken(String clientId, String clientSecret, ManagedExecutorService service)
throws MalformedURLException, InterruptedException, ExecutionException, TimeoutException {
long now = System.currentTimeMillis();
if (accessToken != null && now < expiryTimeMs - REFRESH_BEFORE_EXPIRY_MS) {
AuthenticationContext context = new AuthenticationContext(AUTHORITY, false, service);
AuthenticationCallback<AuthenticationResult> callback = new AuthenticationCallback<AuthenticationResult>() {
@Override
public void onSuccess(AuthenticationResult result) {
log.info("received token");
}
@Override
public void onFailure(Throwable exc) {
throw new RuntimeException(exc);
}
};
log.info("requesting token");
Future<AuthenticationResult> future = context.acquireToken(RESOUCE,
new ClientCredential(clientId, clientSecret), callback);
// wait for access token
AuthenticationResult result = future.get(30, TimeUnit.SECONDS);
// cache token and expiration
accessToken = result.getAccessToken();
expiryTimeMs = result.getExpiresAfter();
}
return accessToken;
}
}
import java.net.MalformedURLException;
导入java.net.URI;
导入java.net.URISyntaxException;
导入java.time.Duration;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.Future;
导入java.util.concurrent.TimeUnit;
导入java.util.concurrent.TimeoutException;
导入javax.enterprise.concurrent.ManagedExecutorService;
导入org.apache.log4j.Logger;
导入com.microsoft.aad.adal4j.AuthenticationCallback;
导入com.microsoft.aad.adal4j.AuthenticationContext;
导入com.microsoft.aad.adal4j.AuthenticationResult;
导入com.microsoft.aad.adal4j.ClientCredential;
导入microsoft.exchange.webservices.data.core.ExchangeService;
导入microsoft.exchange.webservices.data.core.WebProxy;
导入microsoft.exchange.webservices.data.core.enumeration.misc.ConnectingIdType;
导入microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
导入microsoft.exchange.webservices.data.misc.ImpersonatedUserId;
/**
*用于获取用于EWS应用程序的访问令牌。缓存
*令牌,并在到期前5分钟刷新。
*
*@作者斯蒂芬·奥黑尔
*
*/
公共最终类MsEwsTokenProvider{
私有静态最终记录器log=Logger.getLogger(MsEwsTokenProvider.class);
私有静态最终字符串EWS_URL=”https://outlook.office365.com/EWS/Exchange.asmx";
私有静态最终字符串资源=”https://outlook.office365.com";
私有静态最终字符串TENANT\u NAME=“在此处输入您的租户名称”;
私有静态最终字符串权限=”https://login.microsoftonline.com/“+承租人姓名;
私有静态最终长时间刷新\u到期前\u MS=持续时间.of分钟(5).toMillis();
私有静态长过期;
私有静态字符串accessToken;
/**
*接受OAuth2令牌并配置{@link exchangeseservice}。
*
*@param令牌
*@param senderAddr
*@param traceListener
*@param mailboxAddr
*@返回一个已配置并经过身份验证的{@link ExchangeService}
*@URISyntaxException
*@抛出异常
*/
公共静态ExchangeService getAuthenticatedService(字符串令牌、字符串发送者地址、,
TraceListener(TraceListener)引发URI语法异常,异常{
ExchangeService服务=新的ExchangeService(ExchangeVersion.Exchange2010_SP2);
服务。setTraceListener(traceListener);
service.getHttpHeaders().put(“授权”、“承载人”+令牌);
service.getHttpHeaders().put(“X-AnchorMailbox”,senderAddr);
//setWebProxy(新的WebProxy(proxyHost,proxyPort));
setUrl(新URI(EWS_URL));
setImpersonatedUserId(新的ImpersonatedUserId(connectingType.PrincipalName,senderAddr));
回程服务;
}
/**
*使用Azure Active Directory库获取访问令牌的简单方法。
*
*认证地址:https://login.microsoftonline.com/
*
*@param clientId
*-AzureAD应用程序的客户端id
*@param clientSecret
*-克莱
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import com.microsoft.aad.adal4j.AuthenticationCallback;
import com.microsoft.aad.adal4j.AuthenticationContext;
import com.microsoft.aad.adal4j.AuthenticationResult;
import com.microsoft.aad.adal4j.ClientCredential;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.WebProxy;
import microsoft.exchange.webservices.data.core.enumeration.misc.ConnectingIdType;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.misc.ImpersonatedUserId;
/**
* Entry point.
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// Pro tip: make sure to set your proxy configuration here if needed
// and exclude outlook.office365.com from proxy SSL inspection.
String clientId = "your AzureAD application client id";
String clientSecret = "your AzureAD application client secret";
String tenantName = "your tenant";
String recipientAddr = "recipient@yourdomain.com";
String senderAddress = "yourO365@mailbox.com";
TraceListener traceListener = new ITraceListener() {
@Override
public void trace(String traceType, String traceMessage) {
// TODO log it, do whatever...
}
};
// I used a ManagedExecutorService provided by glassfish but you can
// use an ExecutorService and manage it yourself.
String token = MsEwsTokenProvider.getAccesToken(clientId, clientSecret, service);
// don't log this in production!
System.out.println("token=" + token);
// test mailbox read access
System.out.println("geting emails");
try (ExchangeService service = MsEwsTokenProvider.getAuthenticatedService(token, senderAddress)) {
listInboxMessages(service, senderAddress);
}
// send a message
System.out.println("sending a message");
try (ExchangeService service = getAuthenticatedService(token, senderAddress, traceListener)) {
sendTestMessage(service, recipientAddr, senderAddress);
}
System.out.println("finished");
}
public static void sendTestMessage(ExchangeService service, String recipientAddr, String senderAddr)
throws Exception {
EmailMessage msg = new EmailMessage(service);
msg.setSubject("Hello world!");
msg.setBody(MessageBody.getMessageBodyFromText("Sent using the EWS Java API."));
msg.getToRecipients().add(recipientAddr);
msg.send();
msg.setSender(new EmailAddress(senderAddr));
}
public static void listInboxMessages(ExchangeService service, String mailboxAddr) throws Exception {
ItemView view = new ItemView(50);
Mailbox mb = new Mailbox(mailboxAddr);
FolderId folder = new FolderId(WellKnownFolderName.Inbox, mb);
FindItemsResults<Item> result = service.findItems(folder, view);
result.forEach(i -> {
try {
System.out.println("subject=" + i.getSubject());
} catch (ServiceLocalException e) {
e.printStackTrace();
}
});
}