SpringBoot实现短信验证码校验

本文欢迎转载,转载请注明出处,谢谢~(作者:喝酒不骑马 Colton_Null)
from CSDN


有关阿里云通信短信服务验证码的发送,请参考我的另一篇博文
Springboot实现阿里云通信短信业务实现短信验证码的发送
本文将对验证码的校验思路进行讲解。

思路

用户输入手机号后,点击按钮获取验证码。并设置冷却时间,防止用户频繁点击。
后台生成验证码并发送到用户手机上,根据验证码、时间及一串自定义秘钥生成MD5值,并将时间也传回到前端。
用户输入验证码后,将验证码和时间传到后台。后台先用当前时间减去前台传过来的时间验证是否超时。如果没有超时,就用用户输入的验证码 + 时间 + 自定义秘钥生成MD5值与之前的MD5值比较,如果相等则验证码校验通过,如果不等则说明验证码输入错误校验失败。
原理有点像解方程:
xyz经过一种不可逆运算得到A,将y和A传给用户,z后台保留,用户填写x1后,将x1 y A传回后台,后台再用x1 y z经过不可逆运算得到A1,如果A1和A相等,则验证码校验通过。

前端的实现

本例基于BootStrap,html代码中有BootStrap样式。如果你不想用BootStrap,可以将class样式去掉。效果如图所示。
这里写图片描述
html代码如下:

<div class="form-group has-feedback">
    <input type="tel" class="form-control"  id="phone" placeholder="请输入手机号" maxlength=11>
    <span class="glyphicon glyphicon-earphone form-control-feedback"></span>
</div>
<div class="row">
    <div class="col-xs-6 pull_left">
        <div class="form-group">
            <input class="form-control" id="msg_num" placeholder="请输入验证码">
        </div>
    </div>
    <div class="col-xs-6 pull_center">
        <div class="form-group">
            <input type="button" class="btn btn-block btn-flat" id="verify_refresh" onclick="getMsgNum(this)" value="免费获取验证码">
        </div>
    </div>
</div>

<div class="col-xs-12 pull_center">
    <button type="button" class="btn btn-block btn-flat" onclick="validateNum()">验证</button>
</div>

js代码(基于jQuery)

var messageData;
var wait = 120; // 短信验证码120秒后才可获取下一个

/**
 * 获取验证码
 * @param that
 */
function getMsgNum(that) {
    var phoneNumber = $('#phone').val();
    setButtonStatus(that); // 设置按钮倒计时
    var obj = {
        phoneNumber: phoneNumber
    };

    $.ajax({
        url: httpurl + '/sendMsg', // 后台短信发送接口
        type: 'POST',
        dataType: 'json',
        contentType: "application/json",
        async: false, //false 同步
        data: JSON.stringify(obj),
        xhrFields: {
            withCredentials: true
        },
        success: function (result) {
            if(result.code == '200') {
                messageData = result.data;
            }else {
                alert("错误码:" + data.code + "  错误信息:" + data.message);
            }
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            console.log(XMLHttpRequest.status);
            console.log(XMLHttpRequest.readyState);
            console.log(textStatus);
        }
    });
}
/**
 * 设置按钮状态
 */
function setButtonStatus(that) {
    if (wait == 0) {
        that.removeAttribute("disabled");
        that.value="免费获取验证码";
        wait = 60;
    } else {
        that.setAttribute("disabled", true);
        that.value=wait+"秒后可以重新发送";
        wait--;
        setTimeout(function() {
            setButtonStatus(that)
        }, 1000)
    }
}

/**
* 注册按钮
*/
function validateNum() {
    var data = {
        msgNum: inputMsgNum,
        tamp: messageData.tamp,
        hash: messageData.hash
    };

    $.ajax({
        url: httpurl + '/validateNum', // 验证接口
        type: 'POST',
        dataType: 'json',
        contentType: "application/json",
        data: JSON.stringify(data),
        async: false, //false 同步
        success: function (data) {
           //业务处理
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            console.log(XMLHttpRequest.status);
            console.log(XMLHttpRequest.readyState);
            console.log(textStatus);
        }
    });
}

其中setButtonStatus()方法用于设置按钮冷却状态。效果如下图
这里写图片描述

后台的实现

private static final String KEY = "abc123"; // KEY为自定义秘钥

    @RequestMapping(value = "/sendMsg", method = RequestMethod.POST, headers = "Accept=application/json")
    public Map<String, Object> sendMsg(@RequestBody Map<String,Object> requestMap) {
        String phoneNumber = requestMap.get("phoneNumber").toString();
        String randomNum = CommonUtils.createRandomNum(6);// 生成随机数
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, 5);
        String currentTime = sf.format(c.getTime());// 生成5分钟后时间,用户校验是否过期
        sengMsg(); //此处执行发送短信验证码方法
        String hash =  MD5Utils.getMD5Code(KEY + "@" + currentTime + "@" + randomNum);//生成MD5值
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("hash", hash);
        resultMap.put("tamp", currentTime);
        return resultMap; //将hash值和tamp时间返回给前端
    }

    @RequestMapping(value = "/validateNum", method = RequestMethod.POST, headers = "Accept=application/json")
    public Map<String, Object> validateNum(@RequestBody Map<String,Object> requestMap) {
        String requestHash = requestMap.get("hash").toString();
        String tamp = requestMap.get("tamp").toString();
        String msgNum = requestMap.get("msgNum").toString();
        String hash = MD5Utils.getMD5Code(KEY + "@" + tamp + "@" + msgNum);
        if (tamp.compareTo(currentTime) > 0) {
            if (hash.equalsIgnoreCase(requestHash)){
                //校验成功
            }else {
                //验证码不正确,校验失败
            }
        } else {
                // 超时
        }
    }

========= 2018-10-26更新 =========
添加了MD5Utils工具类源码

public class MD5Utils {

    public static String getMD5Code(String content) {
        return Hashing.md5().newHasher().putString(content, Charsets.UTF_8).hash().toString();
    }
}

总结

以上就是基于SpringBoot的验证码校验方法。希望本文能对你有所帮助。

可以通过以下步骤使用springboot实现手机验证码登录: 1. 集成Spring Security依赖 在`pom.xml`文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 2. 实现UserDetailsService接口 创建一个类实现`UserDetailsService`接口,并在其中实现从数据库中获取用户信息的逻辑。例如: ``` @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String phoneNumber) throws UsernameNotFoundException { User user = userRepository.findByPhoneNumber(phoneNumber); if (user == null) { throw new UsernameNotFoundException("User not found with phoneNumber: " + phoneNumber); } return new org.springframework.security.core.userdetails.User(user.getPhoneNumber(), user.getPassword(), new ArrayList<>()); } } ``` 3. 配置Spring Security 在`application.properties`文件中配置Spring Security相关属性: ``` # 禁用CSRF保护,因为我们将使用手机验证码进行登录 security.enable-csrf=false # 配置登录页面和处理登录请求的控制器 spring.security.loginProcessingUrl = /login spring.security.loginPage = /login.html ``` 4. 创建登录页面 创建一个名为`login.html`的登录页面,包含一个表单,用于输入手机号和验证码。例如: ``` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <h2>Login</h2> <form action="/login" method="post"> <div> <label for="phoneNumber">Phone Number:</label> <input type="text" id="phoneNumber" name="phoneNumber" required> </div> <div> <label for="code">Code:</label> <input type="text" id="code" name="code" required> <button type="button" id="sendCode">Send Code</button> </div> <button type="submit">Login</button> </form> <script> // 发送验证码的逻辑 document.getElementById("sendCode").addEventListener("click", function() { var phoneNumber = document.getElementById("phoneNumber").value; // 调用后端API发送验证码 // ... }); </script> </body> </html> ``` 5. 实现发送验证码API 创建一个控制器,用于处理发送验证码的API请求。例如: ``` @RestController public class SMSController { @PostMapping("/sendCode") public ResponseEntity<?> sendCode(@RequestParam("phoneNumber") String phoneNumber) { // 调用发送短信验证码的服务 // ... return ResponseEntity.ok().build(); } } ``` 6. 实现登录API 创建一个控制器,用于处理登录API请求。在该控制器中,使用`AuthenticationManager`和`TokenBasedRememberMeServices`来实现登录逻辑。例如: ``` @RestController public class LoginController { @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenBasedRememberMeServices rememberMeServices; @PostMapping("/login") public ResponseEntity<?> login(@RequestParam("phoneNumber") String phoneNumber, @RequestParam("code") String code, HttpServletRequest request, HttpServletResponse response) { // 校验验证码是否正确 // ... // 创建一个UsernamePasswordAuthenticationToken,以便交给AuthenticationManager进行验证 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(phoneNumber, code); // 让AuthenticationManager进行验证,并返回一个Authentication对象 Authentication authentication = authenticationManager.authenticate(token); // 让TokenBasedRememberMeServices进行处理,并返回一个RememberMeAuthenticationToken对象 RememberMeAuthenticationToken rememberMeToken = rememberMeServices .autoLogin(request, response); // 将两个Authentication对象合并成一个 Authentication mergedAuthentication = new PreAuthenticatedAuthenticationToken( authentication.getPrincipal(), authentication.getCredentials(), Stream.concat(authentication.getAuthorities().stream(), rememberMeToken.getAuthorities().stream()) .collect(Collectors.toList())); // 在SecurityContextHolder中存储合并后的Authentication对象 SecurityContextHolder.getContext().setAuthentication(mergedAuthentication); // 登录成功,返回一个空响应 return ResponseEntity.ok().build(); } } ``` 这样,我们就实现了使用springboot实现手机验证码登录。需要注意的是,该代码仅为示例,实际场景中可能需要根据具体需求进行修改。
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值