一砂簡訊傳送(免費試用)實現驗證碼登入
阿新 • • 發佈:2020-12-24
一砂簡訊傳送(免費試用)
昨日在阿里雲市場發現一個很便宜的簡訊傳送平臺,現記錄食用方式如下
1. 雲市場連結
【國際簡訊/國內簡訊】海外簡訊介面 國外簡訊 國內簡訊 簡訊通知 簡訊驗證 營銷簡訊 簡訊群發 (免費試用)
購買簡訊包後可以在阿里雲控制檯->雲市場->已購買的服務看到如下資訊
2. 需要的依賴
<dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency>
3. 建立工具類
import com.alibaba.fastjson.JSONObject; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import java.util.HashMap; import java.util.Map; /** * @author 楓葉 * @version 1.0 * @date 2020/12/22 */ public class SmsUtil { public static int send(String mobile) { String host = "https://intlsms.market.alicloudapi.com"; String path = "/comms/sms/sendmsgall"; String method = "POST"; String appcode = "第一步中獲取的AppCode"; int mobileCode = (int) ((Math.random() * 9 + 1) * 100000); Map<String, String> headers = new HashMap<String, String>(); //最後在header中的格式(中間是英文空格)為Authorization:APPCODE headers.put("Authorization", "APPCODE " + appcode); //根據API的要求,定義相對應的Content-Type headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); Map<String, String> querys = new HashMap<>(); Map<String, String> bodys = new HashMap<>(); //傳送結果回執地址(可選) // bodys.put("callbackUrl", "http://test.dev.esandcloud.com"); bodys.put("channel", "0"); bodys.put("mobile", "+86" + mobile); //模板id,這裡使用預設模板 bodys.put("templateID", "0000000"); //訊息內容,後面的5代表驗證碼過期時間 bodys.put("templateParamSet", mobileCode + ", 5"); try { /** * 重要提示如下: * HttpUtils請從 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java * 下載 * * 相應的依賴請參照 * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml */ HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys); //獲取response的body JSONObject resp = JSONObject.parseObject(EntityUtils.toString(response.getEntity())); /** 正確的返回如下 { "code":"0000", "msg":"成功。", "externalId":"f9a57d7e9c3a11ea801e02429b292a1b", "requestId":"20200522224610325cxnpasmd" } */ if ("0000".equals(resp.getString("code"))) { return mobileCode; } else { System.out.println("錯誤!"); System.out.println(resp); } } catch (Exception e) { e.printStackTrace(); } return -1; } }
headers引數如下 api參考
HttpUtils如下
import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author 楓葉 * @version 1.0 * @date 2020/12/22 */ public class HttpUtils { /** * get * * @param host * @param path * @param method * @param headers * @param querys * @return * @throws Exception */ public static HttpResponse doGet(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception { HttpClient httpClient = wrapClient(host); HttpGet request = new HttpGet(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } return httpClient.execute(request); } /** * post form * * @param host * @param path * @param method * @param headers * @param querys * @param bodys * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, Map<String, String> bodys) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (bodys != null) { List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>(); for (String key : bodys.keySet()) { nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); } UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8"); formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); request.setEntity(formEntity); } return httpClient.execute(request); } /** * Post String * * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (StringUtils.isNotBlank(body)) { request.setEntity(new StringEntity(body, "utf-8")); } return httpClient.execute(request); } /** * Post stream * * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPost(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPost request = new HttpPost(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (body != null) { request.setEntity(new ByteArrayEntity(body)); } return httpClient.execute(request); } /** * Put String * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, String body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPut request = new HttpPut(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (StringUtils.isNotBlank(body)) { request.setEntity(new StringEntity(body, "utf-8")); } return httpClient.execute(request); } /** * Put stream * @param host * @param path * @param method * @param headers * @param querys * @param body * @return * @throws Exception */ public static HttpResponse doPut(String host, String path, String method, Map<String, String> headers, Map<String, String> querys, byte[] body) throws Exception { HttpClient httpClient = wrapClient(host); HttpPut request = new HttpPut(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (body != null) { request.setEntity(new ByteArrayEntity(body)); } return httpClient.execute(request); } /** * Delete * * @param host * @param path * @param method * @param headers * @param querys * @return * @throws Exception */ public static HttpResponse doDelete(String host, String path, String method, Map<String, String> headers, Map<String, String> querys) throws Exception { HttpClient httpClient = wrapClient(host); HttpDelete request = new HttpDelete(buildUrl(host, path, querys)); for (Map.Entry<String, String> e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } return httpClient.execute(request); } private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException { StringBuilder sbUrl = new StringBuilder(); sbUrl.append(host); if (!StringUtils.isBlank(path)) { sbUrl.append(path); } if (null != querys) { StringBuilder sbQuery = new StringBuilder(); for (Map.Entry<String, String> query : querys.entrySet()) { if (0 < sbQuery.length()) { sbQuery.append("&"); } if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) { sbQuery.append(query.getValue()); } if (!StringUtils.isBlank(query.getKey())) { sbQuery.append(query.getKey()); if (!StringUtils.isBlank(query.getValue())) { sbQuery.append("="); sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8")); } } } if (0 < sbQuery.length()) { sbUrl.append("?").append(sbQuery); } } return sbUrl.toString(); } private static HttpClient wrapClient(String host) { HttpClient httpClient = new DefaultHttpClient(); if (host.startsWith("https://")) { sslClient(httpClient); } return httpClient; } private static void sslClient(HttpClient httpClient) { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] xcs, String str) { } @Override public void checkServerTrusted(X509Certificate[] xcs, String str) { } }; ctx.init(null, new TrustManager[] { tm }, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = httpClient.getConnectionManager(); SchemeRegistry registry = ccm.getSchemeRegistry(); registry.register(new Scheme("https", 443, ssf)); } catch (KeyManagementException ex) { throw new RuntimeException(ex); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } } }
4. 建立web介面實現驗證碼傳送
這裡使用了session,在前後端分離中應使用中心快取技術或資料庫
/**
* @author 楓葉
* @version 1.0
* @date 2020/12/22
*/
@WebServlet(value = "/sms/send", name = "sms")
public class SmsServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
BufferedReader reader = req.getReader();
JSONObject mobileJson = JSONObject.parseObject(reader.readLine());
String mobile = mobileJson.getString("mobile");
//這裡應該查詢資料庫獲取手機號對應的使用者,若沒有使用者則建立新使用者,並繫結手機號
JSONObject token = (JSONObject) req.getSession().getAttribute(mobile);
if (token != null) {
long curren = System.currentTimeMillis();
Long timeOut = token.getLong("timeOut");
if (curren - timeOut > 60 * 1000) {
//重複請求驗證碼
resp.getWriter().println(DataResponse.error("操作過於頻繁請1分鐘後再試。"));
return;
}
}
int mobileCode = SmsUtil.send(mobile);
if (mobileCode > 0) {
//傳送驗證碼成功
token = new JSONObject();
token.put("mobileCode", mobileCode);
token.put("timeOut", System.currentTimeMillis());
req.getSession().setAttribute(mobile, token);
resp.getWriter().println(DataResponse.ok());
return;
}
resp.getWriter().println(DataResponse.error());
}
}
5. 建立web介面實現簡訊驗證碼登入
這裡使用了session,在前後端分離中應使用中心快取技術或資料庫
/**
* @author 楓葉
* @version 1.0
* @date 2020/12/22
*/
@WebServlet(value = "/sms/login", name = "login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
JSONObject json = JSONObject.parseObject(req.getReader().readLine());
String mobile = json.getString("mobile");
Integer mobileCode = json.getInteger("mobileCode");
JSONObject token = (JSONObject) req.getSession().getAttribute(mobile);
System.out.println("token: "+token);
//未獲取驗證碼
if (token == null) {
resp.getWriter().println(DataResponse.error(400, "請先獲取驗證碼。"));
return;
}
long timeOut = System.currentTimeMillis();
//已有驗證碼
if (timeOut - token.getLong("timeOut") > (5 * 60 * 1000)) {
//驗證碼過期
resp.getWriter().println(DataResponse.error(420, "驗證碼過期,請重新獲取。"));
req.getSession().removeAttribute(mobile);
return;
}
if (token.getInteger("mobileCode").equals(mobileCode)) {
//驗證碼正確
req.getSession().setAttribute("yongHu", mobile);
resp.getWriter().println(DataResponse.ok("登入成功!").put("data: ",mobile));
req.getSession().removeAttribute(mobile);
} else {
//驗證碼錯誤。
resp.getWriter().println(DataResponse.error("驗證碼錯誤。"));
}
}
}
6. 上面用到的返回封裝類DataResponse如下
public class DataResponse{
private final Map<String,Object> result;
@Override
public String toString() {
//這裡也用到了fastJSON並且設定了日期的格式化格式
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd hh:mm:ss";
return JSON.toJSONString(result,SerializerFeature.WriteDateUseDateFormat);
}
public DataResponse(Integer code,String msg,Object data){
result = new HashMap<>();
result.put("code",code);
result.put("msg",msg);
result.put("data",data);
}
public DataResponse(Integer code,String msg){
this(code,msg,null);
}
public DataResponse() {
result=new HashMap<>();
}
public DataResponse put(String key,Object value){
result.put(key,value);
return this;
}
public static DataResponse ok(){
return new DataResponse(200,"成功!");
}
public static DataResponse ok(String msg){
return new DataResponse(200,msg);
}
public static DataResponse ok(int code,String msg){
return new DataResponse(code,msg);
}
public static DataResponse ok(String msg,Object data){
return new DataResponse(200,msg,data);
}
public static DataResponse ok(int code,String msg,Object data){
return new DataResponse(200,msg,data);
}
public static DataResponse error(){
return new DataResponse(500,"伺服器錯誤,操作失敗!");
}
public static DataResponse error(String msg){
return new DataResponse(500,msg);
}
public static DataResponse error(int code,String msg){
return new DataResponse(code,msg);
}
public Object get(String key){
return result.get(key);
}
public Object getData(){
return result.get("data");
}
public void setCode(int code) {
result.put("code",code);
}
public void setMsg(String msg) {
result.put("msg",msg);
}
public void setData(Object data) {
result.put("data",data);
}
}
7. 測試
前端關鍵js程式碼如下
//狀態機是否已經發送驗證碼
var mobileFlag = false;
//重新發送驗證碼的間隔時間(秒)
var reSend = 60;
var intervalID;
$("#mobileSend").click(function () {
let reg = /^1([3,4,5,6,7,8,9])\d{9}$/;
let mobile = $("#mobile").val();
if (!(reg.test(mobile))) {
alert("手機號碼有誤,請重填");
//將游標移到手機號輸入框中
document.getElementById("mobile").focus();
return false;
}
$.ajax({
url: "/sms/send",
type: "post",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({
mobile: mobile
}),
success: function (resp) {
if (resp.code === 200) {
mobileFlag = true;
$("#mobileSend").attr("disabled", true)
//頁面顯示倒計時
intervalID = setInterval(function () {
let mobileSend = $("#mobileSend");
mobileSend.val(reSend-- + "秒後可重新發送");
if (reSend < 0) {
clearInterval(intervalID);
mobileSend.removeAttr("disabled");
reSend = 60;
mobileSend.val("重新發送");
}
}, 1000);
} else {
alert("傳送驗證碼失敗,請稍後再試!");
}
},
error: function (xhr) {
alert("錯誤:" + xhr.msg);
}
})
})
$("#mobileLogin").click(function () {
if (!mobileFlag) {
alert("請先獲取驗證碼。")
return;
}
let mobile = $("#mobile").val();
let mobileCode = $("#mobileCode").val();
$.ajax({
url: "/sms/login",
dataType: "json",
type: "post",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({
mobile: mobile,
mobileCode: mobileCode
}),
success: function (data) {
console.log(data)
if (data.code === 200) {
alert("登入成功");
//跳轉頁面
window.location = "/";
} else {
alert("登入失敗 " + data.msg);
}
},
error: function (xhr) {
alert("伺服器異常,請稍後再試!");
}
})
})