目录
Redis实现手机验证码----未完成
了解阿里云的用户权限操作
1、开启子用户
2、新建一个用户组(设置添加权限sms)
3、创建一个用户(具体用来操作的账号)
4、得到AccessKey(id,密码)
开通阿里云短信服务
9.1、实现原理
- 使用工具类生成4位或6位的数字验证码
- 校验手机号为合法后通过短信微服务发送验证码
- 将手机号作为key,验证码作为value存入redis中,并设置一个过期时间
- 用户进行登录/注册时通过key(手机号)到redis中取出验证码
- 进行验证码比对,若匹配则登录/注册通过,随机删除redis中的key-value
9.2、实现
1、校验手机号是否合法的工具类
public class FormUtils {
private static Pattern NUMBER_PATTERN = Pattern.compile("^[1][3,4,5,7,8,9][0-9]{9}$");
/**
* 手机号验证
*/
public static boolean isMobile(String str) {
//验证手机号的正则表达式
return NUMBER_PATTERN.matcher(str).matches();
}
}
2、生成验证码的工具类
public class RandomUtils {
private static final Random random = new Random();
private static final DecimalFormat fourdf = new DecimalFormat("0000");
private static final DecimalFormat sixdf = new DecimalFormat("000000");
public static String getFourBitRandom() {
return fourdf.format(random.nextInt(10000));
}
public static String getSixBitRandom() {
return sixdf.format(random.nextInt(1000000));
}
/**
* 给定数组,抽取n个数据
* @param list
* @param n
* @return
*/
public static ArrayList getRandom(List list, int n) {
Random random = new Random();
HashMap<Object, Object> hashMap = new HashMap<Object, Object>();
// 生成随机数字并存入HashMap
for (int i = 0; i < list.size(); i++) {
int number = random.nextInt(100) + 1;
hashMap.put(number, i);
}
// 从HashMap导入数组
Object[] robjs = hashMap.values().toArray();
ArrayList r = new ArrayList();
// 遍历数组并打印数据
for (int i = 0; i < n; i++) {
r.add(list.get((int) robjs[i]));
System.out.print(list.get((int) robjs[i]) + "\t");
}
System.out.print("\n");
return r;
}
}
3、短信微服务Controller
@Slf4j
@CrossOrigin
@RestController
@Api(tags = "短信管理控制器")
@RequestMapping("/api/sms")
public class ApiSmsController {
@Autowired
private SmsService smsService;
@Autowired
private RedisTemplate redisTemplate;
/***
* 根据传入的手机号来生成并发送验证码
* 并将验证码存入redis缓存
* @param mobile 手机号
* @return
*/
@GetMapping("send/{mobile}")
@ApiOperation("一个用于生成验证码,并将验证码存入redis中的接口")
public R getCode(@PathVariable("mobile") String mobile) throws ClientException {
//0 校验手机号是否合法
if(StringUtils.isBlank(mobile) || !FormUtils.isMobile(mobile)) {
//如果手机号为空或手机号不合法
log.error("手机号不合法!");
// new GrainException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
return R.error().message("手机号不正确!").code(28001);
}
//1 使用工具类生成生成验证码
String checkCode = RandomUtils.getSixBitRandom();
//2 发送验证码
smsService.send(mobile,checkCode);
//3 存储验证码到redis
//使用redisTemplate,使用手机号作为键,保存时长为5分钟
redisTemplate.opsForValue().set(mobile,checkCode,5, TimeUnit.MINUTES);
return R.ok().message("短信发送成功!");
}
}
4、短信微服务Service层
@Slf4j
@Service
public class SmsServiceImpl implements SmsService {
@Autowired
private SmsProperties smsProperties;
@Override
public void send(String mobile, String checkCode) throws ClientException, ClientException {
//调用短信发送SDK,创建client对象
DefaultProfile profile = DefaultProfile.getProfile(
smsProperties.getRegionId(),
smsProperties.getKeyId(),
smsProperties.getKeySecret());
IAcsClient client = new DefaultAcsClient(profile);
//组装请求参数
CommonRequest request = new CommonRequest();
request.setSysMethod(MethodType.POST);
request.setSysDomain("dysmsapi.aliyuncs.com");
request.setSysVersion("2017-05-25");
request.setSysAction("SendSms");
request.putQueryParameter("RegionId", smsProperties.getRegionId());
request.putQueryParameter("PhoneNumbers", mobile);
request.putQueryParameter("SignName", smsProperties.getSignName());
request.putQueryParameter("TemplateCode", smsProperties.getTemplateCode());
Map<String, Object> param = new HashMap<>();
param.put("code", checkCode);
//将包含验证码的集合转换为json字符串
Gson gson = new Gson();
request.putQueryParameter("TemplateParam", gson.toJson(param));
//发送短信
CommonResponse response = client.getCommonResponse(request);
//得到json字符串格式的响应结果
String data = response.getData();
//解析json字符串格式的响应结果
HashMap<String, String> map = gson.fromJson(data, HashMap.class);
String code = map.get("Code");
String message = map.get("Message");
//配置参考:短信服务->系统设置->国内消息设置
//错误码参考:
//https://help.aliyun.com/document_detail/101346.html?spm=a2c4g.11186623.6.613.3f6e2246sDg6Ry
//控制所有短信流向限制(同一手机号:一分钟一条、一个小时五条、一天十条)
if ("isv.BUSINESS_LIMIT_CONTROL".equals(code)) {
log.error("短信发送过于频繁 " + "【code】" + code + ", 【message】" + message);
throw new GrainException(ResultCodeEnum.SMS_SEND_ERROR_BUSINESS_LIMIT_CONTROL);
}
if (!"OK".equals(code)) {
log.error("短信发送失败 " + " - code: " + code + ", message: " + message);
throw new GrainException(ResultCodeEnum.SMS_SEND_ERROR);
}
}
}
5、用户注册微服务Controller
@Slf4j
@CrossOrigin
@RestController
@Api(tags = "会员管理控制器")
@RequestMapping("/api/ucenter/member")
public class ApiMemberController {
@Autowired
private MemberService memberService;
@ApiOperation("会员注册")
@PostMapping("register")
public R register(@RequestBody RegisterVo registerVo) {
memberService.register(registerVo);
return R.ok().message("注册成功!");
}
}
6、用户注册微服务Service
@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private MemberMapper memberMapper;
@Override
public void register(RegisterVo registerVo) {
String nickname = registerVo.getNickname();
String mobile = registerVo.getMobile();
String code = registerVo.getCode();
String password = registerVo.getPassword();
if(StringUtils.isBlank(mobile) || !FormUtils.isMobile(mobile)) {
throw new GrainException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
}
if(StringUtils.isBlank(nickname) || StringUtils.isBlank(password) || StringUtils.isBlank(code)) {
throw new GrainException(ResultCodeEnum.PARAM_ERROR);
}
//校验验证码
String checkCode = (String)redisTemplate.opsForValue().get(mobile);
if(!StringUtils.equals(code,checkCode)) {
//如果用户输入验证码和redis中验证码不相等
//校验失败
throw new GrainException(ResultCodeEnum.CODE_ERROR);
}
//判断用户手机号是否注册
QueryWrapper<Member> memberQueryWrapper = new QueryWrapper<>();
memberQueryWrapper.eq("mobile",mobile);
Integer result = memberMapper.selectCount(memberQueryWrapper);
if(result > 0) {
throw new GrainException(ResultCodeEnum.REGISTER_MOBLE_ERROR);
}
//注册
Member member = new Member();
member.setNickname(nickname);
member.setMobile(mobile);
//密码需要加密
member.setPassword(MD5.encrypt(password));
member.setAvatar("http://tiebapic.baidu.com/forum/w%3D580/sign=21e19fd45010b912bfc1f6f6f3fcfcb5/c0d5d04b20a44623e5077d0d8f22720e0ef3d78e.jpg");
member.setDisabled(false);
memberMapper.insert(member);
//将redis缓存中的验证码删除
redisTemplate.delete(mobile);
}
}
9.3、测试
启动短信微服务和用户注册微服务,使用Swagger进行测试
1、使用短信微服务向指定手机号发送验证码
正在上传…重新上传取消
2、查看Redis缓存和短信
短信
3、打开用户中心微服务进行测试
4、结果
swagger提示注册成功
redis缓存中该键值对被删除
数据库