当前位置: 首页 > 面试题库 >

使用imap和accountmanager令牌访问Gmail

吴安和
2023-03-14
问题内容

我正在尝试使用从Android的AccountManager接收的令牌而不是使用用户名和密码来实现IMAP gmail客户端。

Google为该IMAP示例提供了oauth2 http://code.google.com/p/google-mail-
oauth2-tools/source/browse/#svn%2Ftrunk%2Fjava%2Fcom%2Fgoogle%2Fgoogle%2Fcode%2Fsamples%2Foauth2



http: //code.google.com/p/google-mail-
oauth2-tools/wiki/JavaSampleCode

public static IMAPStore connectToImap(String host,
                                    int port,
                                    String userEmail,
                                    String oauthToken,
                                    boolean debug) throws Exception {
Properties props = new Properties();
props.put("mail.imaps.sasl.enable", "true");
props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
Session session = Session.getInstance(props);
session.setDebug(debug);

final URLName unusedUrlName = null;
IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
final String emptyPassword = "";
store.connect(host, port, userEmail, emptyPassword);
return store;

}

public static void main(String args[]) throws Exception {
if (args.length != 2) {
  System.err.println(
      "Usage: OAuth2Authenticator <email> <oauthToken>");
  return;
}
String email = args[0];
String oauthToken = args[1];

initialize();

IMAPStore imapStore = connectToImap("imap.gmail.com",
                                    993,
                                    email,
                                    oauthToken,
                                    true);
System.out.println("Successfully authenticated to IMAP.\n");

}

但是,当我运行上面的代码时,出现了“空用户名或密码”的异常。有人可以告诉我如何使用xoauth2的imap访问gmail吗?谢谢。

更新2013/02/20,下面是调试日志

 02-19 17:27:20.098  1905: 1905 I/System.out : setDebug: JavaMail version 1.4.1    
 02-19 17:27:20.098  1905: 1905 I/System.out : mail.imap.fetchsize: 16384    
 02-19 17:27:20.106  1905: 1905 I/System.out : enable SASL    
 02-19 17:27:20.106  1905: 1905 I/System.out : SASL mechanisms allowed: XOAUTH2    
 02-19 17:27:21.340  1905: 1905 I/System.out : * OK Gimap ready for requests from 36.224.98.49 z8if14713202igb.53
 02-19 17:27:21.348  1905: 1905 I/System.out : A0 CAPABILITY
 02-19 17:27:21.598  1905: 1905 I/System.out : * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2
 02-19 17:27:21.598  1905: 1905 I/System.out : A0 OK Thats all she wrote! z8if14713202igb.53
 02-19 17:27:21.614  1905: 1905 I/System.out : IMAP DEBUG: AUTH: XOAUTH    
 02-19 17:27:21.614  1905: 1905 I/System.out : IMAP DEBUG: AUTH: XOAUTH2    
 02-19 17:27:21.614  1905: 1905 I/System.out : DEBUG: protocolConnect login, host=imap.gmail.com, user=2104176@gmail.com, password=<non-null>    
 02-19 17:27:21.622  1905: 1905 I/System.out : IMAP SASL DEBUG: Mechanisms: XOAUTH2    
 02-19 17:27:21.817  1905: 1905 I/System.out : IMAP SASL DEBUG: Failed to create SASL client: myjavax.security.sasl.SaslException: Cannot instantiate class com.research.oauth.OAuth2SaslClientFactory [Caused by java.lang.InstantiationException: can't instantiate class com.research.oauth.OAuth2SaslClientFactory]
  02-19 17:27:21.817  1905: 1905 I/System.out : A1 LOGIN 2104176@gmail.com ""
 02-19 17:27:22.036  1905: 1905 I/System.out : A1 NO Empty username or password. z8if14713202igb.53
 02-19 17:27:22.044  1905: 1905 D/test       : javax.mail.AuthenticationFailedException: Empty username or password. z8if14713202igb.53

我使用yor mail.jar和我的应用程序
无法创建SASL客户端:myjavax.security.sasl.SaslException:无法实例化com.research.oauth.OAuth2SaslClientFactory类
,然后应用程序使用空密码登录gmail。请帮助我找出问题所在,谢谢!


问题答案:

您是否打算在OAuth2Provider中更改软件包名称?我在用该代码进行测试时忘记了它。

public static final class OAuth2Provider extends Provider {
private static final long serialVersionUID = 1L;

public OAuth2Provider() {
  super("Google OAuth2 Provider", 1.0,
        "Provides the XOAUTH2 SASL Mechanism");
  put("SaslClientFactory.XOAUTH2",
      "com.example.testjavamail.OAuth2SaslClientFactory");
}

}

就像我在另一个答案中所说的那样,我仅测试了连接,但是它对我有用。

更新

这是我使用的代码,基本上是示例代码,真正改变了Java Mail中对SASL支持的移植。

public class OAuth2Authenticator {
private static final Logger logger = Logger
        .getLogger(OAuth2Authenticator.class.getName());
private static Session mSession;

public static final class OAuth2Provider extends Provider {
    private static final long serialVersionUID = 1L;

    public OAuth2Provider() {
        super("Google OAuth2 Provider", 1.0,
                "Provides the XOAUTH2 SASL Mechanism");
        put("SaslClientFactory.XOAUTH2",
                "com.example.testjavamail.OAuth2SaslClientFactory");
    }
}

public static void initialize() {
    Security.addProvider(new OAuth2Provider());
}

public static IMAPStore connectToImap(String host, int port,
        String userEmail, String oauthToken, boolean debug)
        throws Exception {
    Properties props = new Properties();
    props.put("mail.imaps.sasl.enable", "true");
    props.put("mail.imaps.sasl.mechanisms", "XOAUTH2");
    props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
    Session session = Session.getInstance(props);
    session.setDebug(debug);

    final URLName unusedUrlName = null;
    IMAPSSLStore store = new IMAPSSLStore(session, unusedUrlName);
    final String emptyPassword = "";
    store.connect(host, port, userEmail, emptyPassword);
    return store;
}

public static SMTPTransport connectToSmtp(String host, int port,
        String userEmail, String oauthToken, boolean debug)
        throws Exception {
    Properties props = new Properties();
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.starttls.required", "true");
    props.put("mail.smtp.sasl.enable", "true");
    props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
    props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
    mSession = Session.getInstance(props);
    mSession.setDebug(debug);

    final URLName unusedUrlName = null;
    SMTPTransport transport = new SMTPTransport(mSession, unusedUrlName);
    // If the password is non-null, SMTP tries to do AUTH LOGIN.
    final String emptyPassword = null;
    transport.connect(host, port, userEmail, emptyPassword);

    return transport;
}

public synchronized void testImap(String user, String oauthToken) {
    try {

        initialize();


        IMAPStore imapStore = connectToImap("imap.gmail.com", 993, user,
                oauthToken, true);

    } catch (Exception e) {
        Log.d("test", e.toString());
    }

}

public class ByteArrayDataSource implements DataSource {
    private byte[] data;
    private String type;

    public ByteArrayDataSource(byte[] data, String type) {
        super();
        this.data = data;
        this.type = type;
    }

    public ByteArrayDataSource(byte[] data) {
        super();
        this.data = data;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getContentType() {
        if (type == null)
            return "application/octet-stream";
        else
            return type;
    }

    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(data);
    }

    public String getName() {
        return "ByteArrayDataSource";
    }

    public OutputStream getOutputStream() throws IOException {
        throw new IOException("Not Supported");
    }
}

}

这是来自Java Mail的调试。顺便说一句,发布您的调试日志,它应该有助于了解发生了什么问题

02-06 10:18:11.805: I/System.out(7434): DEBUG: setDebug: JavaMail version 1.4.1
02-06 10:18:11.905: I/System.out(7434): DEBUG: mail.imap.fetchsize: 16384
02-06 10:18:12.025: I/System.out(7434): DEBUG: enable SASL
02-06 10:18:12.040: I/System.out(7434): DEBUG: SASL mechanisms allowed: XOAUTH2
02-06 10:18:12.600: I/System.out(7434): * OK Gimap ready for requests from 2.233.xxx.xxx  2if1471965eej.3
02-06 10:18:12.605: I/System.out(7434): A0 CAPABILITY
02-06 10:18:12.635: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 XYZZY SASL-IR AUTH=XOAUTH AUTH=XOAUTH2
02-06 10:18:12.635: I/System.out(7434): A0 OK Thats all she wrote! 2if1471965eej.3
02-06 10:18:12.645: I/System.out(7434): IMAP DEBUG: AUTH: XOAUTH
02-06 10:18:12.645: I/System.out(7434): IMAP DEBUG: AUTH: XOAUTH2
02-06 10:18:12.645: I/System.out(7434): DEBUG: protocolConnect login, host=imap.gmail.com, user=xxx@gmail.com, password=<non-null>
02-06 10:18:12.650: I/System.out(7434): IMAP SASL DEBUG: Mechanisms: XOAUTH2
02-06 10:18:12.695: I/System.out(7434): IMAP SASL DEBUG: SASL client XOAUTH2
02-06 10:18:12.695: I/System.out(7434): A1 AUTHENTICATE XOAUTH2
02-06 10:18:12.720: I/System.out(7434): + 
02-06 10:18:12.720: I/System.out(7434): IMAP SASL DEBUG: challenge:  :
02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: callback length: 1
02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: callback 0: myjavax.security.auth.callback.NameCallback@41760f78
02-06 10:18:12.730: I/System.out(7434): IMAP SASL DEBUG: response: user=xxx@gmail.comauth=Bearer ya29.... :
02-06 10:18:12.735: I/System.out(7434): dXNlcj1hbGVhbGVtYXp6b3R0aUBnbWFpbC5jb20BYXV0aD1CZWFyZXIgeWEyOS5BSEVTNlpRYklPeU8xU09sR01WSEo3X2tqVzlVdzNYY1RvODBtQ0hyWFVacjRsYlhIdwEB
02-06 10:18:12.870: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE
02-06 10:18:12.870: I/System.out(7434): A1 OK xxx@gmail.com My NAME authenticated (Success)
02-06 10:18:12.870: I/System.out(7434): A2 CAPABILITY
02-06 10:18:13.160: I/System.out(7434): * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE
02-06 10:18:13.160: I/System.out(7434): A2 OK Success


 类似资料:
  • 我已经阅读了JWT和访问令牌和刷新令牌。我知道您必须在很短的时间(分钟)内设置访问令牌过期,并在过期时使用刷新令牌获取新的访问令牌。 我不清楚三件事: 谁检查访问令牌是否过期?客户端是否通过发送过期的访问令牌和刷新来检查并请求新的访问代码? 谁检查刷新令牌是否过期?(显然刷新令牌也需要过期,尽管需要更长的时间才能过期)。 在我看来,如果刷新令牌过期,则必须提示用户重新登录。在某些情况下(移动应用)

  • 我目前正在尝试使用ADFS 2016认证angular 7应用程序(使用angular-oauth2-oidc)。到目前为止,它工作得很好。当我访问应用程序时,我被重定向到ADFS登录页面,在那里输入我的凭据并获得令牌。 现在,当应用程序调用web API时,它在请求头中发送访问令牌。ADFS返回的访问令牌如下所示: 问题是web API必须知道进行调用的用户的ID(因为在应用程序级别定义了一些权

  • 我正在使用Lusita的PHP Oauth库(https://github.com/Lusitanian/PHPoAuthLib)。 在用户在我的应用程序中获得授权后,我收到了访问令牌和访问令牌密钥的值。现在有了这些值,我想对API进行身份验证调用。如何使用Access Token、Access Token Secret以及Consumer Key和Consumer Secret的值进行调用?我不

  • 这是我的身份验证流程: 用户登录后收到两个令牌(具有过期时间的访问令牌和没有过期时间的刷新令牌) 对于每个用户,刷新令牌存储在数据库中名为refreshTokens的json列中(这是一个数组) 在客户端,访问令牌和刷新令牌都存储在本地存储器上 当需要验证用户时,如果访问令牌过期,将使用刷新令牌创建一个新的访问令牌,并将其发送回用户并保持用户登录 当用户注销时,数据库中存储的刷新令牌(在refre

  • null 很抱歉太啰嗦了。 提前谢了。

  • 我试图弄清楚我应该如何坚持身份验证。 假设用户使用电子邮件和密码成功进行身份验证。然后服务器生成并返回两个令牌: accesstoken(jwt过期15分钟)将存储在浏览器存储中 refreshtoken(jwt过期7天)作为安全cookie 当将访问令牌存储在本地存储(或会话存储)中时,React 应用程序将简单地检查它是否存在于存储中并继续渲染私有路由。因此,这意味着如果用户有一个无效/被盗的