1.具备条件
1.阿里云开通短信服务
进入阿里云搜索短信就有对应的短信服务,支付宝购买后进入短信控制台,会有对应的短信服务等信息。包括国内学习、业务统计、系统设置等。
注意:签名和模板不支持个人用户申请未上线业务
2.控制台测试
填写对应信息即可,手机就会收到验证码信息。
2.java整合短信服务
1.代码开发
1.获取 AccessKey和secret-key
因为之前做oss对象存储的时候已经获取过AccessKey和secret-key,所以需要在用户中绑定并授权短信服务即可。
2.SpringBoot整合阿里云短信
首先看下官方文档的介绍与说明。
1.pom文件
<dependency><groupId>com.aliyun</groupId><artifactId>dysmsapi20170525</artifactId><version>2.0.18</version>
</dependency>
2.配置文件
spring.cloud.nacos.discovery.server-addr:nacos服务注册地址
alicloud.secrect-key:密钥
alicloud.access-key:密钥
sms.endpoint:地域节点
sms.templateCode:模板
3.封装组件
其实就是把官方文档的代码拿过来自己用。
@Component
@Data
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms") //和配置文件绑定
public class SmsComponent {// private String host;
// private String path;
// private String templateId;
// private String appcode;@Value("${spring.cloud.alicloud.access-key}")private String accessId;@Value("${spring.cloud.alicloud.secret-key}")private String accessKey;/*** 配置文件对应的*/private String endpoint;private String templateCode;
//public void sendSmsCode(String phone,String code) throws Exception {
//
//
// String method = "POST";
//
// Map<String, String> headers = new HashMap<String, String>();
// //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
// 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<String, String>();
// Map<String, String> bodys = new HashMap<String, String>();
// bodys.put("mobile", phone);
// bodys.put("tag", code);
// bodys.put("templateId", templateId);
//
//
// try {
//
// HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
// System.out.println(response.toString());
// //获取response的body
// System.out.println(EntityUtils.toString(response.getEntity()));
// } catch (Exception e) {
// e.printStackTrace();
// }
// }Config config = new Config()// 您的 AccessKey ID.setAccessKeyId(accessId)// 您的 AccessKey Secret.setAccessKeySecret(accessKey);// 访问的域名config.endpoint = endpoint;Client client = new Client(config);SendSmsRequest sendSmsRequest = new SendSmsRequest().setSignName("阿里云短信测试").setTemplateCode(templateCode).setPhoneNumbers(phone).setTemplateParam("{\"code\":\""+code+"\"}");RuntimeOptions runtime = new RuntimeOptions();SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, runtime);System.out.println(sendSmsResponse);}}
4.发送短信接口
@ResponseBody@GetMapping("/sms/sendCode")public R sendCode(@RequestParam("phone") String phone) throws Exception {String redisCode = stringRedisTemplate.opsForValue().get(AuthConstant.SMS_CODE_CACHE_PREFIX + phone);if (!StringUtils.isEmpty(redisCode)) {long currentTime = Long.parseLong(redisCode.split("_")[1]);//系统时间减去当前时间小于60s不能发送if (System.currentTimeMillis() - currentTime < 60000) {return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMsg());}}//接口防刷//验证码的再次校验 redis保存 存key->手机号 value->验证码 sms:code:1234567898--->123456String code = UUID.randomUUID().toString().substring(0, 5);String subString = code + "_" + System.currentTimeMillis();//redis缓存验证码 防止同一个手机号在60s内再次发送验证码stringRedisTemplate.opsForValue().set(AuthConstant.SMS_CODE_CACHE_PREFIX + phone, subString, 10, TimeUnit.MINUTES);feignService.sendCode(phone, code);return R.ok();}
需要将前端传递的手机号进行发送短信收取验证码判断,如果redis中为空调取短信发送服务(通过feign),如果redis不为空,判断系统时间减去当前时间小于60s不能发送,这样有效防止接口防刷恶意操作。前端注册通过手机号调起后端接口,后端通过uuid等技术生成验证码并调取短信服务接口,使用户收取验证码。
3.MD5&MD5盐值加密
1.MD5
Message Digest algorithm 5,信息摘要算法
- 压缩性:任意长度的数据,算出的 MD5 值长度都是固定的;
- 容易计算:从原数据计算出 MD5 值很容易;
- 抗修改性:对原数据进行任何改动,哪怕只修改 1 个字节,所得到的 MD5 值都有很大区别;
- 强抗碰撞:想找到两个不同的数据,使它们具有相同的 MD5 值是非常困难的;
- 不可逆
@Testvoid contextLoads() {// e10adc3949ba59abbe56e057f20f883e
// md5不能直接用来存储加密密码//可破解 值一直不变 抗修改性: 利用彩虹表 暴力破解法// 盐值加密
// String s = DigestUtils.md5Hex("123456");
// System.out.println(s);
//
// //加盐:$1$+八位字符 每次盐值加密不一样
// String s1 = Md5Crypt.md5Crypt(s.getBytes(),"$1$qwertyui");//$1$qwertyui$vP2GtrM4.h4RUK.3HGS9J.
// System.out.println(s1);//BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String encode = bCryptPasswordEncoder.encode("123456");
// $2a$10$1lc96GWrG7.Lte4f9FsniOAUbpc4t4oaPhXpyG3OiLAxrfsjXqdB6
// $2a$10$2gXOTIfzQDw4VYKhKWNWreNUxCiySPnhAhJiCVLTaXyo6vlPGDPbSboolean matches = bCryptPasswordEncoder.matches("123456", "$2a$10$2gXOTIfzQDw4VYKhKWNWreNUxCiySPnhAhJiCVLTaXyo6vlPGDPbS");System.out.println(encode+"========>"+matches);}
encode产生的和123456始终都会匹配。
@Overridepublic MemberEntity login(MemberLoginVo vo) {//获取用户名String loginAccount = vo.getLoginAccount();//获取用户的密码String pagePassword = vo.getPassword();//去数据库查询MemberEntity memberEntity = baseMapper.selectOne(new QueryWrapper<MemberEntity>().eq("username", loginAccount).or().eq("mobile", loginAccount));if (memberEntity == null) {//登录失败return null;} else {//从数据库返回的密码字段值String password = memberEntity.getPassword();BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();//用页面提交的代码和数据库注册的盐值进行匹配boolean b = passwordEncoder.matches(pagePassword, password);if (b) {return memberEntity;} else {return null;}}