用Authenticator的子类进行身份验证及策略模式
在前面的文章中,我们都是把登录邮箱是必需的用户名、密码预先地写在代码中进行编译,不能在邮件发送程序运行时再给定。假如我们修改了邮箱登录密码,那么原来编译好的文件就不能再用了,这样子做的缺点很明显:邮箱登录时的用户身份认证不灵活。
在 JavaMail 中,可以通过 extends Authenticator 抽象类,在子类中覆盖父类中的 getPasswordAuthentication() 方法,就可以实现以不同的方式来进行登录邮箱时的用户身份认证。JavaMail 中的这种设计是使用了策略模式(Strategy),具体的请参看相关文章。
在我们的代码中,我们设计了一种简单的 SimpleAuthenticator 子类通过构造函数传入用户名和密码,而另一种 GUIAuthenticator 子类则使用 GUI 界面的形式进行身份认证,它可以使得程序在运行时弹出输入对话框来让用户提交用户名和密码,具体的请看下面运行图。
代码实现:
- importjava.util.Date;
- importjava.util.Properties;
- importjava.util.StringTokenizer;
- importjavax.mail.Authenticator;
- importjavax.mail.Transport;
- importjavax.mail.Message.RecipientType;
- importjavax.mail.PasswordAuthentication;
- importjavax.mail.Session;
- importjavax.mail.internet.InternetAddress;
- importjavax.mail.internet.MimeMessage;
- importjavax.swing.JOptionPane;
- //普通的通过构造函数传入身份验证信息的Authenticator子类
- classSimpleAuthenticatorextendsAuthenticator{
- privateStringuser;
- privateStringpwd;
- publicSimpleAuthenticator(Stringuser,Stringpwd){
- this.user=user;
- this.pwd=pwd;
- }
- @Override
- protectedPasswordAuthenticationgetPasswordAuthentication(){
- returnnewPasswordAuthentication(user,pwd);
- }
- }
- //具有弹出输入对话框的Authenticator子类
- classGUIAuthenticatorextendsAuthenticator{
- @Override
- protectedPasswordAuthenticationgetPasswordAuthentication(){
- Stringuser;
- Stringpwd;
- //弹出输入对话框
- Stringresult=JOptionPane.showInputDialog("请输入用户名和密码,以','隔开!");
- StringTokenizerst=newStringTokenizer(result,",");
- user=st.nextToken();
- pwd=st.nextToken();
- returnnewPasswordAuthentication(user,pwd);
- }
- }
- /**
- *使用Authenticator子类进行用户身份认证
- *@authorhaolloyin
- */
- publicclassUseAuthenticatorSender{
- privateStringsmtpServer="smtp.126.com";
- privateStringfrom="[email protected]";
- privateStringto="[email protected]";
- privateStringsubject="使用Authenticator子类进行用户身份认证";
- privateStringbody="使用Authenticator子类进行用户身份认证的测试!!!";
- publicvoidsendMails(Authenticatorauth)throwsException{
- //设置协议、是否身份验证、服务器等信息
- Propertiesprops=newProperties();
- props.setProperty("mail.transport.protocol","smtp");
- props.setProperty("mail.smtp.auth","true");
- props.setProperty("mail.host",smtpServer);
- //通过传入的参数获得Authenticator子类对象
- Sessionsession=Session.getInstance(props,auth);
- session.setDebug(true);
- MimeMessagemsg=newMimeMessage(session);
- msg.setFrom(newInternetAddress(from));
- msg.setRecipient(RecipientType.BCC,newInternetAddress(to));
- msg.setSubject(subject);
- msg.setSentDate(newDate());
- msg.setText(body);
- msg.saveChanges();
- /*
- *由于Session对象中注册了Authenticator子类对象,因此可以直接
- *从该Authenticator子类对象中获取登录的相关信息,故直接使用
- *Transport抽象类中静态send()方法来简化代码编写
- */
- Transport.send(msg);
- }
- //测试
- publicstaticvoidmain(String[]args)throwsException{
- UseAuthenticatorSendersender=newUseAuthenticatorSender();
- //这里体现了使用策略模式的好处,客户端可以选择使用
- //具体的哪一种身份验证方式来提交信息
- //Authenticatorauth=newSimpleAuthenticator("testhao","123456");
- Authenticatorauth=newGUIAuthenticator();
- sender.sendMails(auth);
- }
- }
两种测试结果(只需要在main()方法中注释掉其中的一行则可):
1、使用 SimpleAuthenticator 子类:
2、使用 GUIAuthenticator 子类:
注:程序在运行到用户身份验证时会自动弹出下面的输入对话框,由于上面的代码中的 Session 对象启动了 JavaMail API 调试功能,所以这个现象可以很明显地从控制台中得知。
通过上面使用 Authenticator 的具体子类来实现不同的身份验证方式,我们大概地了解到策略模式的好处,我们还可以在设计一个从网页中或者数据库表中获取登录信息的 Authenticator 子类,而客户端在使用时却可以不受影响。
小结:
Authenticator 类的这种结构设计是设计模式运用在实际应用中的体现,从 JavaMail 的帮助文档中可以看到 Authenticator 类中的其他方法都是 protected final 修饰的,这与策略模式(Strategy)的设计一样。