一砂短信发送(免费试用)实现验证码登录

一砂短信发送(免费试用)

昨日在阿里云市场发现一个很便宜的短信发送平台,现记录食用方式如下

1. 云市场链接

【国际短信/国内短信】海外短信接口 国外短信 国内短信 短信通知 短信验证 营销短信 短信群发 (免费试用)

image-20201224101417799

购买短信包后可以在阿里云控制台->云市场->已购买的服务看到如下信息

image-20201224111313173

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参考

image-20201224103930858

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("服务器异常,请稍后再试!");
        }
    })
})
posted @ 2020-12-24 12:53  Maple_XL  阅读(906)  评论(0编辑  收藏  举报