安卓+SpringBoot短信验证

Posted weixin_52173611

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓+SpringBoot短信验证相关的知识,希望对你有一定的参考价值。

安卓+SpringBoot短信验证

原理

客户端进入登陆页面,输入手机号,点击"获取验证码",这时候客户端会先做一个判断,看手机号是不是符合规范,不是的话就弹出提示框提示"手机号不规范,请重新输入",如果是规范的手机号,客户端就带上手机号作为参数向服务端发送请求,服务端接收到这个请求就调用发送短信的业务层(官方有工具类,输入参数即可),随机生成四位数字,然后可以以这个手机号为key,验证码为value存在redis,设置一个过期时间(一般都是五分钟),然后这个业务层会向这个手机号发送这个随机生成的字符串。

客户端收到短信输入验证码,点击登录,客户端又带上手机号和验证码向服务端发送请求,服务端收到请求首先看redis是不是存在这样的"以客户端提交的这个手机号为key,验证码为value"的键值对,不存在的话那就是验证码过期了,或者手机号,验证填错了,返回验证错误的信息给客户端;如果存在的话,那就验证成功了,那么接下来还要做一个判断,要看看这个手机号注册过没有,在用户注册表中查询有没有这个手机号对应的用户,有的话就是注册过的,那就返回客户端登陆成功的标识,客户端成功登录跳转首页;如果用户注册表中没有对应的用户,可以返回客户端没有注册的信息,也可以顺便用这个手机号注册一个信息,现在一般都是这种流程,注册之后,同样返回客户端登录成功的信息,客户端登陆成功,跳转首页。

流程图:

步骤:

客户端

这是安卓端登录页的代码:

package com.yunyou.fragment.Login;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.yunyou.R;
import com.yunyou.entity.Scenics.JsonRootBean;
import com.yunyou.fragment.PersonalFragment;
import com.yunyou.module.MainActivity;
import com.yunyou.utils.YyHttpRequestOrGetDataFromNet;
import com.yunyou.utils.YySharedPrefUtility;

import org.json.JSONObject;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Create by xie
 * Date: 2021/10/11
 * Time: 0:03
 **/
public class LoginByIdentityCodeFragment extends Fragment implements View.OnClickListener

    private String phone;
    private String vertify;
    private String jsonLoginningInfo;
    private JsonRootBean jsonRootBean;//自己写的实体类,格式化数据
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        final View view = inflater.inflate(R.layout.activity_login_by_identitycode, container, false);
        Button vertify = view.findViewById(R.id.vertify);
        Button loginvertify = view.findViewById(R.id.loginvertify);
        vertify.setOnClickListener(this);
        loginvertify.setOnClickListener(this);


        return view;
    
    //这是碎片的实例化
    public static LoginByIdentityCodeFragment newInstance() 
        Bundle bundle = new Bundle();
        LoginByIdentityCodeFragment fragment = new LoginByIdentityCodeFragment();
        fragment.setArguments(bundle);
        return fragment;
    
    //这是登录的方法
    public void login()
        EditText phoneEditView = getView().findViewById(R.id.phone_account);
        phone = phoneEditView.getText().toString();
        EditText vertifyEditView = getView().findViewById(R.id.edit_passwordvertify);
        vertify = vertifyEditView.getText().toString();
        //正确的手机号
        if(isTruePhone(phone))
//            Toast.makeText(getActivity(),"验证码已发送至"+phone+"五分钟内有效,注意查收哦!",Toast.LENGTH_LONG).show();

            try
                //后端验证登录的接口
                String loginurl = getString(R.string.url2) + "vertify/"+phone+"/"+vertify;;


                jsonLoginningInfo = YyHttpRequestOrGetDataFromNet.doGetJsonStringFromThread(loginurl, "");
                Gson gson = new Gson();
                jsonRootBean = gson.fromJson(jsonLoginningInfo,new TypeToken<JsonRootBean>().getType());
//token 存储

                YySharedPrefUtility.setParam(getActivity(),YySharedPrefUtility.Token,
                        jsonRootBean.getContent().getToken());
                System.out.println("token:"+jsonRootBean.getContent().getToken());
                System.out.println("token:"+jsonRootBean.getMsg());


            
            catch (Exception e) e.printStackTrace();

            //密码正确:服务端返回1
            if (jsonRootBean.getMsg().equals("registerSuccess")) 
                Toast.makeText(getActivity(), "登陆成功", Toast.LENGTH_SHORT).show();
                YySharedPrefUtility.setParam(getActivity(),
                        YySharedPrefUtility.ACCOUNTID, phone);//用户名存起来
                startActivity(new Intent(getActivity(), MainActivity.class));//登录成功跳转首页

            
            //用户名不存在或密码错误:服务端返回-1
            else 
                Toast.makeText(getActivity(), "手机号不存在或验证码不正确", Toast.LENGTH_SHORT).show();
            


        //验证码为空
        else if(vertify.equals(""))
            Toast.makeText(getActivity(),"验证码不能为空",Toast.LENGTH_LONG).show();
        //不是合格的手机号
        else
            Toast.makeText(getActivity(),"不是合格的手机号",Toast.LENGTH_LONG).show();
        
    
    
    
    
    
    //发送验证码
    public void sendSms()
        EditText phoneEditView = getView().findViewById(R.id.phone_account);
        phone = phoneEditView.getText().toString();
        if(!isTruePhone(phone))
            Toast.makeText(getActivity(),"不是合格的手机号"+phone,Toast.LENGTH_LONG).show();
        
        else
            //这里请求url
            try
                String loginByVertifyurl = getString(R.string.url2) + "send/"+phone;
                
                String result = YyHttpRequestOrGetDataFromNet.doGetJsonStringFromThread(loginByVertifyurl,"cdvdv");
                Toast.makeText(getActivity(),"验证码已发送至"+phone+"五分钟内有效,注意查收哦!",Toast.LENGTH_LONG).show();

            
            catch (Exception e) e.printStackTrace();
        
    
    
    
    //验证是否为合格的手机号
    public Boolean isTruePhone(String phone)

//        ^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d8$
//        String PHONE_PATTERN="^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17([0,1,6,7,]))|(18[0-2,5-9]))\\\\d8$";
        String PHONE_PATTERN = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147)|(19[0-9]))\\\\d8$";
        boolean isPhone = Pattern.compile(PHONE_PATTERN).matcher(phone).matches();
        if(isPhone)return true;
        else return false;
    
    /**
     * 8-16个字符,不包含空格,必须包含数字,字母或字符至少两种
     * @param password
     * @return
     */
    public  boolean isPassword(String password)
        String pattern = "(?!.*\\\\s)(?!^[\\\\u4e00-\\\\u9fa5]+$)(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^.8,16$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(password);
        return m.matches();
    

    /**
     * 验证是否为邮箱
     * @param email
     * @return
     */
    public  boolean isEmail(String email)
        String pattern = "^\\\\w+([-+.]\\\\w+)*@\\\\w+([-.]\\\\w+)*\\\\.\\\\w+([-.]\\\\w+)*$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(email);
        return m.matches();
    
    
    //点击事件
    @Override
    public void onClick(View v) 
        switch (v.getId())
                //发送验证码
            case R.id.vertify:
                sendSms();
                break;
                //登录
            case R.id.loginvertify:
                login();
                break;
        
    


服务端

配置redis

服务端为了实现验证码过期的逻辑,要用到redis,那首先就要配置redis,我之前用ssm项目配置redis一直有问题,于是就叫别人帮忙把项目转成了SpringBoot开发

1.下载redis

最好在github,在官网现在只能下载压缩包,压缩文件用也是可以用,但是每次都要手动开启redis服务,重新设置redis密码买比较繁琐,最好在github下载二进制文件安装包,地址如下:

https://github.com/tporadowski/redis/releases

下载后进入redis安装目录进入redis.windows.conf

找到这一行,改成你的密码

然后可能要在redis安装目录下cmd输入redis-server.exe redis.windows.conf执行这个配置文件才会生效

反正最后在双击redis-cli 输入"auth 123456"(自己的密码)出现OK就是设置成功

2.添加依赖

<!--redis-Jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

        <!--spring-reids-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

3.写redis配置文件

applecation.properties

spring.redis.host=localhost
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=123456
#spring.redis.database=0
#连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=30000

RedisConfig配置类读取applecation.properties信息

package com.yunyou.yunyoutest.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisConfig

    @Value("$spring.redis.host")
    private String host;
    @Value("$spring.redis.port")
    private int port;
    @Value("$spring.redis.password")
    private String password;
    @Value("$spring.redis.timeout")
    private int timeout;
    @Value("$spring.redis.jedis.pool.max-active")
    private int maxActive;
    @Value("$spring.redis.jedis.pool.max-idle")
    private int maxIdle;
    @Value("$spring.redis.jedis.pool.max-wait")
    private long maxWait;
    @Value("$spring.redis.jedis.pool.max-idle")
    private int minIdle;

    @Bean
    public JedisPool jedisProvider() 
        try 
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(maxIdle);
            config.setMaxWaitMillis(maxWait);
            config.setMaxTotal(maxActive);
            config.setMinIdle(minIdle);


            JedisPool jedisPool = new JedisPool(config, host, port, timeout, password);
            System.out.println("连接redis" + jedisPool.getResource().toString());
            return jedisPool;
        catch (Exception e)
            System.out.println(e);
            System.out.println(host+port+timeout+ password);
            System.out.println("redis连接失败");
            return null;
        
    

还有一个redis的工具类

package com.yunyou.yunyoutest.util.Redis;




import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.List;
import java.util.Map;

@Component
public class JedisUtils 
    @Autowired(required = false)
    private JedisPool jedisPool;

    /**
     * 获取JedisPool连接池实例
     *
     * @return JedisPool连接池实例(通过Spring生成)
     */
    public JedisPool getJedisPool() 
        return jedisPool;
    

    /**
     * 获取Jedis实例
     *
     * @return Jedis实例
     */
    public Jedis getJedis() 
        return jedisPool.getResource();
    

    /**
     * Redis设置键值对
     *
     * @param key   键
     * @param value 值
     * @return 值
     */
    public String set(String key, String value) 
        return action(jedis -> jedis.set(key, value));
    

    /**
     * Redis获取键对应的值
     *
     * @param key 键
     * @return 值
     */
    public String get(String key) 
        return action(jedis -> jedis.get(key));
    

    /**
     * Redis是否存在当前键
     *
     * @param key 查询的键
     * @return 是否存在
     */
    public Boolean exists(String key) 
        return action(jedis -> jedis.exists(key));
    

    /**
     * 设置Key的过期时间,单位以秒计
     *
     * @param key     键
     * @param seconds 秒数
     * @return 1为设置成功,0为设置失败(Jedis返回的就是Long,不知道为嘛要用Long)
     */
    public Long expire(String key, int seconds) 
        return action(jedis -> jedis.expire(key, seconds));
    

    

以上是关于安卓+SpringBoot短信验证的主要内容,如果未能解决你的问题,请参考以下文章

SpringBoot 实现手机发送短信验证码

安卓ContentObserver模式获取短信用正则自己主动填充验证码

mob免费短信验证码安卓SDK调用方法

springboot实现短信验证码的发送

SpringBoot整合腾讯短信服务发送验证码

Springboot使用session容器存取短信验证码