如何通过OAuth2.0替代密码使用Java Mail连接Outlook邮件服务器?
Java Mail 连接Outlook邮件服务器OAuth2.0认证问题
问题背景
我正在使用Java Mail连接Microsoft Outlook邮件服务器,目前通过PLAIN认证(用户名+密码)可成功连接。由于微软即将禁用Basic Authentication,我希望升级为使用OAuth2.0认证,但替换密码为OAuth2令牌后连接失败。
成功的PLAIN认证代码
Store store = null; String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; Properties props= new Properties(); props.put("mail.imaps.ssl.enable", "true"); props.put("mail.imaps.sasl.enable", "true"); props.put("mail.imaps.port", port); props.put("mail.imaps.auth.mechanisms", "XOAUTH2"); props.put("mail.imaps.sasl.mechanisms", "XOAUTH2"); props.put("mail.imaps.auth.login.disable", "true"); props.put("mail.imaps.auth.plain.disable", "true"); props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY); props.setProperty("mail.imaps.socketFactory.fallback", "false"); props.setProperty("mail.imaps.socketFactory.port", port); props.setProperty("mail.imaps.starttls.enable", "true"); props.put("mail.debug", "true"); props.put("mail.debug.auth", "true"); Session session = Session.getInstance(props); session.setDebug(true); store = session.getStore("imaps"); logger.info("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: "+ port + ", userEmailId: " + userEmailId+", AccessToken: " + oauth2AccessToken); try { Integer iPort = Integer.parseInt(port); store.connect(host, iPort, userEmailId, password); // store.connect(host, iPort, userEmailId, oauth2AccessToken); logger.info("IMAP connected with system properties to Host:" + host + ", Port: "+ port + ", userEmailId: " + userEmailId+", AccessToken: " + oauth2AccessToken); if(store.isConnected()){ logger.info("Connection Established using imap protocol successfully !"); } else { logger.info("Connection not Established using imap protocol"); } } catch (Exception e) { logger.error("Store.Connect failed with the errror: "+e.getMessage()); StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String exceptionAsString = sw.toString(); logger.error(exceptionAsString); } return store;
OAuth2连接失败的修改
将上述代码中的密码连接替换为令牌连接后失败:
store.connect(host, iPort, userEmailId, oauth2AccessToken);
调试日志
DEBUG: JavaMail version 1.5.0-b01 DEBUG: successfully loaded resource: /META-INF/javamail.default.providers DEBUG: Tables of loaded providers DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]} DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]} DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map DEBUG: setDebug: JavaMail version 1.5.0-b01 DEBUG: getProvider() returning javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle] DEBUG IMAPS: mail.imap.fetchsize: 16384 DEBUG IMAPS: mail.imap.ignorebodystructuresize: false DEBUG IMAPS: mail.imap.statuscachetimeout: 1000 DEBUG IMAPS: mail.imap.appendbuffersize: -1 DEBUG IMAPS: mail.imap.minidletime: 10 DEBUG IMAPS: disable AUTH=LOGIN DEBUG IMAPS: disable AUTH=PLAIN DEBUG IMAPS: enable STARTTLS DEBUG IMAPS: enable SASL DEBUG IMAPS: SASL mechanisms allowed: XOAUTH2 DEBUG IMAPS: trying to connect to host "outlook.office365.com", port 993, isSSL true * OK The Microsoft Exchange IMAP4 service is ready. [XXXX] A0 CAPABILITY * CAPABILITY IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+ A0 OK CAPABILITY completed. DEBUG IMAPS: AUTH: PLAIN DEBUG IMAPS: AUTH: XOAUTH2 DEBUG IMAPS: protocolConnect login, host=outlook.office365.com, user=username@email.com, password=<non-null> DEBUG IMAPS: SASL Mechanisms: DEBUG IMAPS: XOAUTH2 DEBUG IMAPS: DEBUG IMAPS: No SASL support A1 LOGIN username@email.com {1479+} XXXXX A1 NO LOGIN failed.
Azure门户提示
Azure门户提示似乎在期待密码而非令牌:
令牌生成代码
返回的字符串看起来是有效的令牌:
String accessToken = null; String clientId = "<client id from azure app registration>" String secret = "<client secret from azure app registration>" - client secret value String authority = "https://login.microsoftonline.com/<tenant-id from azure>/oauth2/v2.0/token"; String scope = "https://outlook.office365.com/.default"; try { ConfidentialClientApplication app = ConfidentialClientApplication.builder(clientId, ClientCredentialFactory.createFromSecret(secret)).authority(authority).build(); // With client credentials flows the scope is ALWAYS of the shape "resource/.default", as the // application permissions need to be set statically (in the portal), and then granted by a tenant administrator ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(Collections.singleton(scope)).build(); CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam); IAuthenticationResult result = future.get(); accessToken = result.accessToken(); if (StringUtils.isBlank(accessToken)) { logger.error("Access token "+accessToken); } } catch(Exception e) { logger.error("Exception in acquiring token: "+e.getMessage(), e); } logger.debug("Access Token : "+accessToken); return accessToken;
疑问
请问如何修改才能通过OAuth2.0连接邮件服务器?
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

