用户登录接口的设计,首先要考虑的是防止用户的账号被暴力破解,常用的是使用谷歌图形验证码,同时还需要对用户每天的“连续”登录错误次数进行限制,假设一个账号用户每天连续登陆的错误次数是十次,那么当用户第十一次输入错误时,就应该锁住当前用户的账户。但是我们真正的目的是为了保证用户的账号安全,屏蔽攻击者的恶意调用的同时,又要保证真实用户的正常使用,此时就应该提供重置登录密码的操作,密码重置成功之后,用户在当天又能恢复登录。其次需要考虑的是用户登录密码在传输过程中的安全性的问题,虽说现在的HTTPS 的安全性已经足够,但是对于一些安全性很高的项目,仍旧需要有自己的加密方式来保护用户的敏感信息,比如我这里使用的RSA加密方法,具体的论述以及使用,请参考我的另一篇博客:https://blog.csdn.net/weixin_42023666/article/details/89706659。
下面废话也不多说,直接上代码,当然了,还是老规矩,只分享service层的代码来陈述具体的思路,至于全套代码无法提供(还请谅解)。另外代码中的注释已经有足够多的解释,千万别忘了他们。
package sy.service.impl;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import DateUtil;
import sy.util.mobile.MobileUtil;
@Service("userService")
public class UserServiceImpl implements UserService {
private static final Logger logger = Logger.getLogger(UserServiceImpl.class);
/**
登录时,当用户输入手机号后,就调用该接口判断当前手机号是否注册,
如果是已经注册过的,后台就会生成rsa公私钥对并将公钥返回给前端;
如果没有注册,就提醒用户当前手机号未注册,以此来提高用户体验
*/
@Override
public Result findUser(String mobile, HttpServletRequest request) {
Result result = new Result();
// 判断传入的手机号格式是否正确
if (StringUtils.isBlank(mobile)) {
result.setSuccess(false);
result.setMsg("缺少必要参数");
return result;
}
mobile = mobile.trim();
// 判断传入的手机号格式是否正确
if (mobile.length() != 11 || !MobileUtil.isMobileNum(mobile)) {
result.setSuccess(false);
result.setMsg("传入的手机号格式不正确");
return result;
}
//查询当前手机号是否注册,此处省略具体的数据库相关的操作
if(未注册){//伪代码,实际使用需换成你自己的dao层查询
result.setSuccess(false);
result.setMsg("当前手机号没有注册");
return result;
}
String rsaPublicKey = "login_rsa_public_" + mobile;
String rsaPrivateKey = "login_rsa_private_" + mobile;
Long rsa = RedisUtils.ttl(rsaPublicKey);
if (rsa > 60 *15+5) {// 原来的公钥有效时间大于15分钟,继续使用
result.setStatus(RedisUtils.get(rsaPublicKey));//该字段保存生成的rsa公钥并返回给前端
} else {
Map<Integer, String> map = RSAEncrypt.genKeyPair();
if (map != null && map.get(0) != null) {
RedisUtils.set(rsaPublicKey, map.get(0), 60 * 120 + 120);// 保存公钥
RedisUtils.set(rsaPrivateKey, map.get(1), 60 * 120 + 150);// 保存私钥,2小时有效
result.setStatus(map.get(0));
}