用JAVA实现Email和短信验证
在Web项目中Email和短信验证是很普遍的情形,下面我们来介绍如何用Java来实现。
1.用JAVA实现Email验证
1.1 Java实现
EmailSender.java实现使用java来发送Email。
代码语言:javascript复制package com.jerry;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.AuthenticationFailedException;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
/**
* 实现邮件发送功能
* @author Administrator
*
*/
public class EmailSender {
private static final Logger logger = LogManager.getLogger(EmailSender.class);
private String host; // 服务器地
private String from; // 发件人
private String to; // 收件人 多个收件人以,分隔
private String title; // 主题
private String content; // 内容
private List<File> attachmentlist ; //附件集
private String username; // 用户名
private String password; // 密码
/**发件人员工编号*/
private String sendEmployeeId;
public String getSendEmployeeId() {
return sendEmployeeId;
}
public void setSendEmployeeId(String sendEmployeeId) {
this.sendEmployeeId = sendEmployeeId;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<File> getAttachmentlist() {
return attachmentlist;
}
public void setAttachmentlist(List<File> attachmentlist) {
this.attachmentlist = attachmentlist;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
private String port;
public EmailSender(String host, String from, String to, String title,
String content, List attachmentlist, String username, String password,String port) {
this.host = host;
this.from = from;
this.to = to;
this.title = title;
this.content = content;
this.attachmentlist = attachmentlist;
this.username = username;
this.password = password;
this.port=port;
}
public EmailSender(String to, String title,
String content, List attachmentlist) {
this.to = to;
this.title = title;
this.content = content;
this.attachmentlist = attachmentlist;
}
/**
* 发送邮件
* @return 发送状态信息 index0:状态 0成功 1失败;index1:描述错误信息
*/
public String[] sendMail(){
String[] result=new String[2];
Session session=null;
Properties props = System.getProperties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.sendpartial", "true");
props.put("mail.smtp.port", port);
if(StringUtils.isBlank(username)){//不需要验证用户名密码
session = Session.getDefaultInstance(props, null);
}else{
props.put("mail.smtp.auth", "true");
EmailAuthenticator auth = new EmailAuthenticator(username, password);
session = Session.getInstance(props, auth);
}
//设置邮件发送信息
try{
// 创建邮件
MimeMessage message = new MimeMessage(session);
// 设置发件人地址
message.setFrom(new InternetAddress(from));
// 设置收件人地址(多个邮件地址)
InternetAddress[] toAddr = InternetAddress.parse(to);
message.addRecipients(Message.RecipientType.TO, toAddr);
// 设置邮件主题
message.setSubject(title);
// 设置发送时间
message.setSentDate(new Date());
// 设置发送内容
Multipart multipart = new MimeMultipart();
MimeBodyPart contentPart = new MimeBodyPart();
contentPart.setText(content);
multipart.addBodyPart(contentPart);
//设置附件
if(attachmentlist!=null && attachmentlist.size()>0){
for(int i = 0 ; i < attachmentlist.size();i ){
MimeBodyPart attachmentPart = new MimeBodyPart();
FileDataSource source = new FileDataSource(attachmentlist.get(i));
attachmentPart.setDataHandler(new DataHandler(source));
attachmentPart.setFileName(MimeUtility.encodeWord(attachmentlist.get(i).getName(), "gb2312", null));
multipart.addBodyPart(attachmentPart);
}
}
message.setContent(multipart);
//登录SMTP服务器
if (StringUtils.isBlank(username)) {
// 不需验证
Transport.send(message);
} else {
// 需要验证
Transport transport = session.getTransport("smtp");
transport.connect();
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
result[0]="0";
result[1]="发送成功";
logger.info("邮件发送成功!发送人:" from);
}catch(MessagingException mex){
result[0]="1";
result[1]="邮件服务器发生错误";
if(mex instanceof AuthenticationFailedException){
result[1]="用户名或密码错误";
}
} catch (Exception e) {
result[0]="1";
result[1]="系统异常";
}
return result;
}
public static void main(String[] args){
String SNMPTServer = "smtp.126.com";
String from="xianggu625@126.com";
String to="xianggu625@126.com";
String title="发送测试报告";
String content="附件为测试报告";
String username="xianggu625@126.com";
String password="VXDUKEHFKHMCKHRT";
String port="25";
List list=new ArrayList();
//list.add(new File("C:\myjava\web\junit.rar"));
EmailSender sender=new EmailSender(SNMPTServer,from,to,title,content,list,username,password,port);
String [] result = sender.sendMail();
System.out.println(result[1] "ffffffffffffffff");
}
}
/**
* class MyAuthenticator用于邮件服务器认证 构造器需要用户名、密码作参数
*/
class EmailAuthenticator extends Authenticator {
private String username = null;
private String password = null;
public EmailAuthenticator(String username, String password) {
this.username = username;
this.password = password;
}
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
}
1.2 邮件服务器端设置
注意:网易,QQ的邮箱password的设置为下图设置的密码。
用手机扫描后,页面会显示密码。
1.3 HTML代码
email.html
代码语言:javascript复制<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>找回密码</title>
</head>
<form method="post" action="jsp/email.jsp" name="myForm">
用户名:<input type="text" name="username" maxlength="50" value=""><br>
邮箱:<input type="Email" name="Email" maxlength="50" value=""><br>
<input type="submit" value="找回密码">
</form>
</body>
</html>
1.4 jsp实现
email.jsp
代码语言:javascript复制<%@ page contentType="text/html; charset=gb2312" %>
<%@ page language="java" %>
<%@ page import="java.util.*" %>
<%@ page import="java.io.File" %>
<%@ page import="java.util.Random" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="java.sql.*" %>
<%@ page import="com.jerry.EmailSender" %>
<%@ page import="cn.com.service.*" %>
<%@ include file="db/checkfromdb.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<%
String name=request.getParameter("username");
String to=request.getParameter("Email");
String code6 = String.valueOf(new Random().nextInt(999999));
String mycode=code.getSHA256StrJava(code6).toString();
Connection conn = connectDB();
ResultSet rs = getrs(name,to,"","",conn);
if(!(rs.getString("mycount")).equals("0")){
String SNMPTServer = "smtp.126.com";
String from="xianggu625@126.com";
String title="找回验证码";
String content="您的验证码为" code6;
String username="xianggu625@126.com";
String password="DXDUYEHFJHMTKHRT";
String port="25";
List list=new ArrayList();
EmailSender sender=new EmailSender(SNMPTServer,from,to,title,content,list,username,password,port);
String [] result = sender.sendMail();
if (result[1].equals("发送成功")){
%>
<title>输入验证码</title>
<script type="text/javascript" src="../js/sh256.js"></script>
<script type="text/javascript" >
function checkcode()
{
var my = document.forms["myForm"]["jym"].value;
if (my.length!=6){
alert("验证码应该为6位!");
return false;
}
my = SHA256(my);
if(my!="<%=mycode%>"){
alert("验证码错误!");
return false;
}else
return true;
}
</script>
</head>
<body>
<form method="post" action="setpassword.jsp" name="myForm" onsubmit="return checkcode()">
验证码:<input type="number" name="jym" maxlength="50" value=""><br>
<input type="submit" value="提交">
</form>
</body>
</html>
<%
session.setAttribute("code" , mycode);
}
session.setAttribute("uername" , name);
}else{
out.print("注册的用户名和Email不匹配,请<a href="../email.html">,重新输入</a>");
}
%>
1.5 使用SH256散列
我们对使用到的6位随机密码进行SH256散列,这个方法在code.java中定义。
代码语言:javascript复制package cn.com.service;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class code {
/**
* 利用java原生的摘要实现SHA256加密
* @param str 加密后的报文
* @return
*/
public static String getSHA256StrJava(String str){
MessageDigest messageDigest;
String encodeStr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
encodeStr = byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodeStr;
}
/**
* 将byte转为16进制
* @param bytes
* @return
*/
private static String byte2Hex(byte[] bytes){
StringBuffer stringBuffer = new StringBuffer();
String temp = null;
for (int i=0;i<bytes.length;i ){
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length()==1){
//1得到一位的进行补0操作
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
}
用户输入通过短信收到的6位编码,在JS端进行SH256编码后进行比对。
注:更安全的做法可以通过Ajax方法来实现。
1.6 安全编码
为了安全性,方式用户在发包以后,黑客截包修改Email地址,所以需要获得Email地址后,需要校验是否与该用户注册的Email用户一致,所以在db目录下建立checkfromdb.jsp,完成这个功能。
代码语言:javascript复制<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="java.util.*" %>
<%@ page import="java.sql.*" %>
<%@ page language="java" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="java.sql.*" %>
<%!
Connection connectDB(){
Connection conn=null;
try{
//驱动程序名
String driverName="com.mysql.jdbc.Driver";
//数据库用户名
String userName="root";
//密码
String userPasswd="123456";
//数据库名
String dbName="ebusiness";
//联结字符串
String url="jdbc:mysql://localhost/" dbName "?user=" userName "&password=" userPasswd;
Class.forName(driverName).newInstance();
conn=DriverManager.getConnection(url);
}catch(Exception e) {
e.printStackTrace();
}
return conn;
}
ResultSet getrs(String name,String email,String phone,String password,Connection conn){
ResultSet rs = null;
try{
//表名
String tableName="goods_user";
String sql = "";
if(password.length()!=0){sql="select count(*) as mycount from " tableName " where username=? and password=?";}
else if(email.length()!=0){sql="select count(*) as mycount from " tableName " where username=? and email=?";}
else if(phone.length()!=0){sql="select count(*) as mycount from " tableName " where username=? and phone=?";}
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,name);
if(password.length()!=0)ps.setString(2,password);
else if(email.length()!=0)ps.setString(2,email);
else if(phone.length()!=0)ps.setString(2,phone);
rs = ps.executeQuery();
rs.next();
}catch(Exception e) {
e.printStackTrace();
}
return rs;
}
%>
1.7 操作界面
操作界面如下:
收到邮件
输入验证码268111,进入修改密码界面。
点击【提交】,可以设置新密码。
2.用JAVA实现短信验证
2.1 短信第三方平台设置
发送短信,需要使用第三方平台,这里我使用的是榛子网(http://sms_developer.zhenzikj.com/zhenzisms_user/index.html),注册登录进去,建议充20元钱,可以发送500条短信。
进入应用管理-我的应用,记住AppId和AppSecret,下面编码的时候要用。
进入短信管理-短信模板,记住模板ID,下面编码的时候要用。编辑内容。
注意:
1. 占位符格式:{数字},从{1}、{2}开始顺序填写。示例: 验证码:{1},{2}内有效,请勿泄漏给他人使用。
2. 每个账号最多创建20个模板
3. 个人账号创建的短信正文模板每个变量取值最多支持12个字。企业认证用户没有变量取值长度限制。
4. 模板中不能含有短信签名,比如【xx】
5. 模板必须体现实际业务,除变量以外的文本内容必须可判读短信含义和使用场景。
特别注意第1条,{1}、{2}我们将在程序中进行变量赋值。我的短信模板为:
“验证码为{1}:1分钟内有效,请勿泄漏给他人使用。”,里面仅有一个变量。
上代码。
2.2 Java代码
GetMessage.java
代码语言:javascript复制package cn.com.service;
import com.zhenzi.sms.ZhenziSmsClient;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class GetMessage {
//短信平台相关参数
//这个不用改
public static String getCode(String memPhone){
String apiUrl = "https://sms_developer.zhenzikj.com";
//榛子云系统上获取
String appId = "109473";
String appSecret = "3592cfbd-0877-4cac-b720-ac4a55cefc77";
try {
//随机生成验证码
String code = String.valueOf(new Random().nextInt(999999));
//将验证码通过榛子云接口发送至手机
ZhenziSmsClient client = new ZhenziSmsClient(apiUrl, appId, appSecret);
Map<String, Object> params = new HashMap<String, Object>();
//前台输入的手机号
params.put("number", memPhone);
params.put("message", code);
//这个模板id对应的是榛子云个人中心的模板id
params.put("templateId", 5948);
String[] templateParams = new String[1];
templateParams[0] = code;
params.put("templateParams", templateParams);
String result = client.send(params);
int length = result.toCharArray().length;
result = result.substring(0,length-1) ","mycode":"" code ""}";
return result;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
在这里:
- String appId = "109473"; //为榛子网的用户ID
- String appSecret = "3592cfbd-0877-4cac-b720-ac4a55cefc77";//为榛子网的用户密码
- …
- params.put("templateId", 5948);//榛子网的模板ID
- String[] templateParams = new String[1]; //向模板中传参数
- templateParams[0] = code;
2.3 HTML代码
phone.html
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>找回密码</title>
</head>
<body>
<form method="post" name="myForm" action="jsp/sms.jsp">
<div>用户名:<input type="text" name="username" maxlength="50" value=""></div>
<div>手机号: <input type="tel" name="number"></div>
<div><button type="submit" class="sub-btn">获取验证码</button></div>
</form>
</body>
</html>
3.4 jsp实现
sms.jsp
代码语言:javascript复制<%@ page contentType="text/html; charset=gb2312" %>
<%@ page language="java" %>
<%@ page import="net.sf.json.JSONObject" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="java.sql.*" %>
<%@ page import="cn.com.service.*" %>
<%@ include file="db/checkfromdb.jsp"%>
<!DOCTYPE html>
<%
String name=request.getParameter("username");
String number=request.getParameter("number");
Connection conn = connectDB();
ResultSet rs = getrs(name,"",number,"",conn);
if(!(rs.getString("mycount")).equals("0")){
String message = GetMessage.getCode(number);
JSONObject json = JSONObject.fromObject(message);
if((json.get("code").toString()).equals("0")&&(json.get("data").toString()).equals("发送成功")){
String mycode = json.get("mycode").toString();
mycode=code.getSHA256StrJava(mycode);
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>输入验证码</title>
<script type="text/javascript" src="../js/sh256.js"></script>
<script type="text/javascript" >
function checkcode()
{
var my = document.forms["myForm"]["jym"].value;
if (my.length!=6){
alert("验证码应该为6位!");
return false;
}
my = SHA256(my);
if(my!="<%=mycode%>"){
alert("验证码错误!");
return false;
}else
return true;
}
</script>
</head>
<form method="post" action="setpassword.jsp" name="myForm" onsubmit="return checkcode()">
验证码:<input type="number" name="jym" maxlength="50" value=""><br>
<input type="submit" value="提交">
</form>
</body>
</html>
<%
session.setAttribute("code" , mycode);
}
session.setAttribute("uername" , name);
}else{
out.print("注册的用户名和手机不匹配,请<a href="../phone.html">,重新输入</a>");
}
%>
用户输入通过短信收到的6位编码,在JS端进行SH256编码后进行比对。
注:更安全的做法可以通过Ajax方法来实现。
3.5安全编码
为了安全性,方式用户在发包以后,黑客截包修改电话号码,所以需要获得电话号码后,需要校验是否与该用户注册的电话号码用户一致,同样调用checkfromdb.jsp中的函数,完成这个功能。
3.6 操作界面
操作界面如下:
手机收到验证码。
输入验证码
点击【提交】,可以设置新密码。
3.SH256 散列js代码实现
sh256.js
代码语言:javascript复制/**
*
* Secure Hash Algorithm (SHA256)
* http://www.webtoolkit.info/
*
* Original code by Angel Marin, Paul Johnston.
*
**/
function SHA256(s){
var chrsz = 8;
var hexcase = 0;
function safe_add (x, y) {
var lsw = (x & 0xFFFF) (y & 0xFFFF);
var msw = (x >> 16) (y >> 16) (lsw >> 16);
return (msw << 16) | (lsw & 0xFFFF);
}
function S (X, n) { return ( X >>> n ) | (X << (32 - n)); }
function R (X, n) { return ( X >>> n ); }
function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }
function core_sha256 (m, l) {
var K = new Array(0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, 0xE49B69C1, 0xEFBE4786, 0xFC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x6CA6351, 0x14292967, 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2);
var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
var W = new Array(64);
var a, b, c, d, e, f, g, h, i, j;
var T1, T2;
m[l >> 5] |= 0x80 << (24 - l % 32);
m[((l 64 >> 9) << 4) 15] = l;
for ( var i = 0; i<m.length; i =16 ) {
a = HASH[0];
b = HASH[1];
c = HASH[2];
d = HASH[3];
e = HASH[4];
f = HASH[5];
g = HASH[6];
h = HASH[7];
for ( var j = 0; j<64; j ) {
if (j < 16) W[j] = m[j i];
else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
h = g;
g = f;
f = e;
e = safe_add(d, T1);
d = c;
c = b;
b = a;
a = safe_add(T1, T2);
}
HASH[0] = safe_add(a, HASH[0]);
HASH[1] = safe_add(b, HASH[1]);
HASH[2] = safe_add(c, HASH[2]);
HASH[3] = safe_add(d, HASH[3]);
HASH[4] = safe_add(e, HASH[4]);
HASH[5] = safe_add(f, HASH[5]);
HASH[6] = safe_add(g, HASH[6]);
HASH[7] = safe_add(h, HASH[7]);
}
return HASH;
}
function str2binb (str) {
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i = chrsz) {
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i2);
}
return bin;
}
function Utf8Encode(string) {
string = string.replace(/rn/g,"n");
var utftext = "";
for (var n = 0; n < string.length; n ) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext = String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext = String.fromCharCode((c >> 6) | 192);
utftext = String.fromCharCode((c & 63) | 128);
}
else {
utftext = String.fromCharCode((c >> 12) | 224);
utftext = String.fromCharCode(((c >> 6) & 63) | 128);
utftext = String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
function binb2hex (binarray) {
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i ) {
str = hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 4)) & 0xF)
hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
}
return str;
}
s = Utf8Encode(s);
return binb2hex(core_sha256(str2binb(s), s.length * chrsz));
}