EWS modern authentication using oauth2.0 : The remote server returned an error: (401)Unauthorized
EWS modern authentication using oauth2.0 : The remote server returned an error: (401)Unauthorized
我正在尝试使用 Microsoft Graph 访问令牌对 Outlook 邮箱(用于从应用程序发送邮件)进行现代身份验证。
我正在从以下代码中成功获取访问令牌:
public class AuthTokenAccess {
public AuthTokenAccess() {}
public static String getAccessToken(String tenantId, String clientId, String clientSecret, String scope)
{
String endpoint = String.format("https://login.microsoftonline.com/%s/oauth2/token", tenantId);
String postBody = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s&scope=%s",
clientId, clientSecret, "https://management.azure.com/", scope);
String accessToken = null;
try{
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
conn.getOutputStream().write(postBody.getBytes());
conn.connect();
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(conn.getInputStream());
//String accessToken = null;
while (parser.nextToken() != JsonToken.END_OBJECT) {
String name = parser.getCurrentName();
if ("access_token".equals(name)) {
parser.nextToken();
accessToken = parser.getText();
}
}
}catch(Exception e) {
}
return accessToken;
}
获得访问令牌后,我将其发送到 ExchangeService:
public ExchangeService getExchangeServiceObj(String emailId, String token, String emailServerURI) throws URISyntaxException {
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
if(service != null) {
service.getHttpHeaders().put("Authorization", "Bearer " + token);
service.getHttpHeaders().put("X-AnchorMailbox", emailId);
service.setUrl(new URI(emailServerURI)); //https://outlook.office365.com/EWS/Exchange.asmx
}
LOGGER.debug("getExchangeServiceObj() {}.", "ends");
return service;
}
在这里,我正在获取 ExchangeService 对象,但是当我尝试发送邮件时 microsoft.exchange.webservices.data.core.service.item.EmailMessage.sendAndSaveCopy() 抛出异常
public void sendMail(String toMail, String ccMail, String subject, String body, String pathOfFileToAttach) {
ExchangeService emailService = getExchangeServiceObj(
ResourceUtils.getPropertyValue("email_user"),
token,
ResourceUtils.getPropertyValue("ews_server"));
if(!StringUtils.hasText(toMail)) {
toMail = ccMail;
}
EmailMessage emessage = new EmailMessage(emailService);
emessage.setSubject(subject);
String strBodyMessage = body;
strBodyMessage = strBodyMessage + "<br /><br />";
LOGGER.info("Body: {} ", body);
MessageBody msg = new MessageBody(BodyType.HTML, strBodyMessage);
emessage.setBody(msg);
emessage.sendAndSaveCopy();
LOGGER.info("Email send {}", "sucessfully");
} catch(Exception e) {
LOGGER.error(Constants.ERROR_STACK_TRACE, e);
throw new CommonException(e);
}
}
尝试了以下范围:
"https://outlook.office.com/EWS.AccessAsUser.All",
"https://graph.microsoft.com/.default"
下面是我使用上面的代码获得的访问令牌:
{"aud": "https://management.azure.com/",
"iss": "https://sts.windows.net/3863b7d0-213d-40f3-a4d0-6cd90452245a/",
“我”:1628068305,
“nbf”:1628068305,
“exp”:1628072205,
"aio": "E2ZgYEjcvsaipUV1wxwxrne/9F4XAAA=",
“appid”:“055eb578-4716-4901-861b-92f2469dac9c”,
“appidacr”:“1”,
"idp": "https://sts.windows.net/3863b7d0-213d-40f3-a4d0-6cd90452245a/",
“oid”:“33688cee-e16e-4d11-8ae0-a804805ea007”,
"rh": "0.AUYA0LdjOD0h80Ck0GzZBFIkWni1XgUWRwFJhhuS8kadrJxGAAA。",
“子”:“33688cee-e16e-4d11-8ae0-a804805ea007”,
“tid”:“3863b7d0-213d-40f3-a4d0-6cd90452245a”,
"uti": "nZUVod_e3EuO_T-Ter-_AQ",
“版本”:“1.0”,
“xms_tcdt”:1626687774
}
如您所见,范围未包含在令牌中。获取token的时候还需要传递其他东西吗
Azure 活动目录设置:
注册申请
2.Create 客户机密
3.Added 重定向 URL
已添加权限
有人可以在这里帮助我吗,我在哪里做错了,或者有其他任何其他方法可以使它工作。谢谢
首先我可以在这里看到一些问题,您使用客户端凭据流程需要您分配应用程序权限并且您只有委托权限,对于 EWS,唯一可用的应用程序权限是 full_access_as_app 参见 https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth(仅限应用部分)
String endpoint = String.format("https://login.microsoftonline.com/%s/oauth2/token", tenantId);
String postBody = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s&scope=%s",
clientId, clientSecret, "https://management.azure.com/", scope);
您混合使用 V1 和 V2 身份验证(请参阅 https://nicolgit.github.io/AzureAD-Endopoint-V1-vs-V2-comparison/) here which won't work (scope will just be ignored) for the v1 endpoint eg what you have in https://login.microsoftonline.com/%s/oauth2/token is the V1 auth endpoint so your request shouldn't include the scope just the resource and that resource should be https://outlook.office.com
我正在尝试使用 Microsoft Graph 访问令牌对 Outlook 邮箱(用于从应用程序发送邮件)进行现代身份验证。 我正在从以下代码中成功获取访问令牌:
public class AuthTokenAccess {
public AuthTokenAccess() {}
public static String getAccessToken(String tenantId, String clientId, String clientSecret, String scope)
{
String endpoint = String.format("https://login.microsoftonline.com/%s/oauth2/token", tenantId);
String postBody = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s&scope=%s",
clientId, clientSecret, "https://management.azure.com/", scope);
String accessToken = null;
try{
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
conn.setRequestMethod("POST");
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setDoOutput(true);
conn.getOutputStream().write(postBody.getBytes());
conn.connect();
JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createParser(conn.getInputStream());
//String accessToken = null;
while (parser.nextToken() != JsonToken.END_OBJECT) {
String name = parser.getCurrentName();
if ("access_token".equals(name)) {
parser.nextToken();
accessToken = parser.getText();
}
}
}catch(Exception e) {
}
return accessToken;
}
获得访问令牌后,我将其发送到 ExchangeService:
public ExchangeService getExchangeServiceObj(String emailId, String token, String emailServerURI) throws URISyntaxException {
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
if(service != null) {
service.getHttpHeaders().put("Authorization", "Bearer " + token);
service.getHttpHeaders().put("X-AnchorMailbox", emailId);
service.setUrl(new URI(emailServerURI)); //https://outlook.office365.com/EWS/Exchange.asmx
}
LOGGER.debug("getExchangeServiceObj() {}.", "ends");
return service;
}
在这里,我正在获取 ExchangeService 对象,但是当我尝试发送邮件时 microsoft.exchange.webservices.data.core.service.item.EmailMessage.sendAndSaveCopy() 抛出异常
public void sendMail(String toMail, String ccMail, String subject, String body, String pathOfFileToAttach) {
ExchangeService emailService = getExchangeServiceObj(
ResourceUtils.getPropertyValue("email_user"),
token,
ResourceUtils.getPropertyValue("ews_server"));
if(!StringUtils.hasText(toMail)) {
toMail = ccMail;
}
EmailMessage emessage = new EmailMessage(emailService);
emessage.setSubject(subject);
String strBodyMessage = body;
strBodyMessage = strBodyMessage + "<br /><br />";
LOGGER.info("Body: {} ", body);
MessageBody msg = new MessageBody(BodyType.HTML, strBodyMessage);
emessage.setBody(msg);
emessage.sendAndSaveCopy();
LOGGER.info("Email send {}", "sucessfully");
} catch(Exception e) {
LOGGER.error(Constants.ERROR_STACK_TRACE, e);
throw new CommonException(e);
}
}
尝试了以下范围: "https://outlook.office.com/EWS.AccessAsUser.All", "https://graph.microsoft.com/.default"
下面是我使用上面的代码获得的访问令牌:
{"aud": "https://management.azure.com/", "iss": "https://sts.windows.net/3863b7d0-213d-40f3-a4d0-6cd90452245a/", “我”:1628068305, “nbf”:1628068305, “exp”:1628072205, "aio": "E2ZgYEjcvsaipUV1wxwxrne/9F4XAAA=", “appid”:“055eb578-4716-4901-861b-92f2469dac9c”, “appidacr”:“1”, "idp": "https://sts.windows.net/3863b7d0-213d-40f3-a4d0-6cd90452245a/", “oid”:“33688cee-e16e-4d11-8ae0-a804805ea007”, "rh": "0.AUYA0LdjOD0h80Ck0GzZBFIkWni1XgUWRwFJhhuS8kadrJxGAAA。", “子”:“33688cee-e16e-4d11-8ae0-a804805ea007”, “tid”:“3863b7d0-213d-40f3-a4d0-6cd90452245a”, "uti": "nZUVod_e3EuO_T-Ter-_AQ", “版本”:“1.0”, “xms_tcdt”:1626687774 }
如您所见,范围未包含在令牌中。获取token的时候还需要传递其他东西吗
Azure 活动目录设置:
注册申请 2.Create 客户机密 3.Added 重定向 URL
已添加权限
有人可以在这里帮助我吗,我在哪里做错了,或者有其他任何其他方法可以使它工作。谢谢
首先我可以在这里看到一些问题,您使用客户端凭据流程需要您分配应用程序权限并且您只有委托权限,对于 EWS,唯一可用的应用程序权限是 full_access_as_app 参见 https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth(仅限应用部分)
String endpoint = String.format("https://login.microsoftonline.com/%s/oauth2/token", tenantId);
String postBody = String.format("grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s&scope=%s",
clientId, clientSecret, "https://management.azure.com/", scope);
您混合使用 V1 和 V2 身份验证(请参阅 https://nicolgit.github.io/AzureAD-Endopoint-V1-vs-V2-comparison/) here which won't work (scope will just be ignored) for the v1 endpoint eg what you have in https://login.microsoftonline.com/%s/oauth2/token is the V1 auth endpoint so your request shouldn't include the scope just the resource and that resource should be https://outlook.office.com