博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用户中心
阅读量:2389 次
发布时间:2019-05-10

本文共 8693 字,大约阅读时间需要 28 分钟。

leyou-user

了解面向接口开发方式

  • 实现数据校验功能
  • 实现短信发送功能
  • 实现注册功能
  • 实现根据用户名和密码查询用户功能

后台功能准备

  • 接口文档
  • 数据结构
CREATE TABLE `tb_user` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `username` varchar(50) NOT NULL COMMENT '用户名',  `password` varchar(32) NOT NULL COMMENT '密码,加密存储',  `phone` varchar(20) DEFAULT NULL COMMENT '注册手机号',  `created` datetime NOT NULL COMMENT '创建时间',  `salt` varchar(32) NOT NULL COMMENT '密码加密的salt值',  PRIMARY KEY (`id`),  UNIQUE KEY `username` (`username`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COMMENT='用户表';

数据结构比较简单,因为根据用户名查询的频率较高,所以我们给用户名创建了索引

在这里插入图片描述
注意:为了安全考虑。这里对password和salt添加了注解**@JsonIgnore,这样在json序列化时,就不会把password和salt返回。**

1.用户名和手机号的校验

判断type的值1:校验用户名2:校验手机号使用selectCount(record)==0

2.发送短信功能

阿里大于	参照demo工程redis	安装	SDR使用:SpringDataRedis/StringRedisTemplate搭建了一个微服务:sms-service,监听rabbitmq的队列,获取到消息之后发送短信1.生成验证码2.发送消息给rabbitMQ的队列3.保存验证码到redis中

阿里大于短信服务

创建短信微服务

因为系统中不止注册一个地方需要短信发送,因此我们将短信发送抽取为微服务:leyou-sms-service,凡是需要的地方都可以使用。

另外,因为短信发送API调用时长的不确定性,为了提高程序的响应速度,短信发送我们都将采用异步发送方式,即:

  • 短信服务监听MQ消息,收到消息后发送短信。
  • 其它服务要发送短信时,通过MQ通知短信微服务。
    在这里插入图片描述

属性抽取

我们首先把一些常量抽取到application.yml中:

leyou:  sms:    accessKeyId: JWffwFJIwada # 你自己的accessKeyId    accessKeySecret: aySRliswq8fe7rF9gQyy1Izz4MQ # 你自己的AccessKeySecret    signName: 乐优商城 # 签名名称    verifyCodeTemplate: SMS_133976814 # 模板名称

然后注入到属性类中:

@ConfigurationProperties(prefix = "leyou.sms")public class SmsProperties {
String accessKeyId; String accessKeySecret; String signName; String verifyCodeTemplate; public String getAccessKeyId() {
return accessKeyId; } public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId; } public String getAccessKeySecret() {
return accessKeySecret; } public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret; } public String getSignName() {
return signName; } public void setSignName(String signName) {
this.signName = signName; } public String getVerifyCodeTemplate() {
return verifyCodeTemplate; } public void setVerifyCodeTemplate(String verifyCodeTemplate) {
this.verifyCodeTemplate = verifyCodeTemplate; }}

工具类

我们把阿里提供的demo进行简化和抽取,封装一个工具类:

@Component@EnableConfigurationProperties(SmsProperties.class)public class SmsUtils {
@Autowired private SmsProperties prop; //产品名称:云通信短信API产品,开发者无需替换 static final String product = "Dysmsapi"; //产品域名,开发者无需替换 static final String domain = "dysmsapi.aliyuncs.com"; static final Logger logger = LoggerFactory.getLogger(SmsUtils.class); public SendSmsResponse sendSms(String phone, String code, String signName, String template) throws ClientException {
//可自助调整超时时间 System.setProperty("sun.net.client.defaultConnectTimeout", "10000"); System.setProperty("sun.net.client.defaultReadTimeout", "10000"); //初始化acsClient,暂不支持region化 IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", prop.getAccessKeyId(), prop.getAccessKeySecret()); DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain); IAcsClient acsClient = new DefaultAcsClient(profile); //组装请求对象-具体描述见控制台-文档部分内容 SendSmsRequest request = new SendSmsRequest(); request.setMethod(MethodType.POST); //必填:待发送手机号 request.setPhoneNumbers(phone); //必填:短信签名-可在短信控制台中找到 request.setSignName(signName); //必填:短信模板-可在短信控制台中找到 request.setTemplateCode(template); //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为 request.setTemplateParam("{\"code\":\"" + code + "\"}"); //选填-上行短信扩展码(无特殊需求用户请忽略此字段) //request.setSmsUpExtendCode("90997"); //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者 request.setOutId("123456"); //hint 此处可能会抛出异常,注意catch SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request); logger.info("发送短信状态:{}", sendSmsResponse.getCode()); logger.info("发送短信消息:{}", sendSmsResponse.getMessage()); return sendSmsResponse; }}

编写消息监听器

接下来,编写消息监听器,当接收到消息后,我们发送短信。

@Component@EnableConfigurationProperties(SmsProperties.class)public class SmsListener {
@Autowired private SmsUtils smsUtils; @Autowired private SmsProperties prop; @RabbitListener(bindings = @QueueBinding( value = @Queue(value = "leyou.sms.queue", durable = "true"), exchange = @Exchange(value = "leyou.sms.exchange", ignoreDeclarationExceptions = "true"), key = {
"sms.verify.code"})) public void listenSms(Map
msg) throws Exception {
if (msg == null || msg.size() <= 0) {
// 放弃处理 return; } String phone = msg.get("phone"); String code = msg.get("code"); if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
// 放弃处理 return; } // 发送消息 SendSmsResponse resp = this.smsUtils.sendSms(phone, code, prop.getSignName(), prop.getVerifyCodeTemplate()); }}

我们注意到,消息体是一个Map,里面有两个属性:

  • phone:电话号码
  • code:短信验证码

Redis保存短信

  • Spring Data Redis
    官网:http://projects.spring.io/spring-data-redis/
    Spring Data Redis,是Spring Data 家族的一部分。 对Jedis客户端进行了封装,与spring进行了整合。可以非常方便的来实现redis的配置和操作
    RedisTemplate基本操作

Spring Data Redis 提供了一个工具类:RedisTemplate。里面封装了对于Redis的五种数据结构的各种操作,包括:

  • redisTemplate.opsForValue() :操作字符串
  • redisTemplate.opsForHash() :操作hash
  • redisTemplate.opsForList():操作list
  • redisTemplate.opsForSet():操作set
  • redisTemplate.opsForZSet():操作zset

其它一些通用命令,如expire,可以通过redisTemplate.xx()来直接调用

5种结构:

  • String:等同于java中的,Map<String,String>
  • list:等同于java中的Map<String,List<String>>
  • set:等同于java中的Map<String,Set<String>>
  • sort_set:可排序的set
  • hash:等同于java中的:`Map<String,Map<String,String>>

StringRedisTemplate

RedisTemplate在创建时,可以指定其泛型类型:

  • K:代表key 的数据类型
  • V: 代表value的数据类型

注意:这里的类型不是Redis中存储的数据类型,而是Java中的数据类型,RedisTemplate会自动将Java类型转为Redis支持的数据类型:字符串、字节、二进制等等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NiThUaj5-1586768198969)(assets/1527250218215.png)]

不过RedisTemplate默认会采用JDK自带的序列化(Serialize)来对对象进行转换。生成的数据十分庞大,因此一般我们都会指定key和value为String类型,这样就由我们自己把对象序列化为json字符串来存储即可。

因为大部分情况下,我们都会使用key和value都为String的RedisTemplate,因此Spring就默认提供了这样一个实现: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-krgSrXxh-1586768198970)(assets/1527256139407.png)]

实现

需要三个步骤:

  • 生成随机验证码
  • 将验证码保存到Redis中,用来在注册的时候验证
  • 发送验证码到leyou-sms-service服务,发送短信

因此,我们需要引入Redis和AMQP:

org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-amqp

添加RabbitMQ和Redis配置:

spring:  redis:    host: 192.168.56.101  rabbitmq:    host: 192.168.56.101    username: leyou    password: leyou    virtual-host: /leyou

另外还要用到工具类,生成6位随机码,这个我们封装到了leyou-common中,因此需要引入依赖:

com.leyou.common
leyou-common
${leyou.latest.version}

NumberUtils中有生成随机码的工具方法:

/** * 生成指定位数的随机数字 * @param len 随机数的位数 * @return 生成的随机数 */public static String generateCode(int len){
len = Math.min(len, 8); int min = Double.valueOf(Math.pow(10, len - 1)).intValue(); int num = new Random().nextInt( Double.valueOf(Math.pow(10, len + 1)).intValue() - 1) + min; return String.valueOf(num).substring(0,len);}

UserController

在leyou-user-service工程中的UserController添加方法:

/** * 发送手机验证码 * @param phone * @return */@PostMapping("code")public ResponseEntity
sendVerifyCode(String phone) {
Boolean boo = this.userService.sendVerifyCode(phone); if (boo == null || !boo) {
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } return new ResponseEntity<>(HttpStatus.CREATED);}

UserService

在Service中添加代码:

@Autowiredprivate StringRedisTemplate redisTemplate;@Autowiredprivate AmqpTemplate amqpTemplate;static final String KEY_PREFIX = "user:code:phone:";static final Logger logger = LoggerFactory.getLogger(UserService.class);public Boolean sendVerifyCode(String phone) {
// 生成验证码 String code = NumberUtils.generateCode(6); try {
// 发送短信 Map
msg = new HashMap<>(); msg.put("phone", phone); msg.put("code", code); this.amqpTemplate.convertAndSend("leyou.sms.exchange", "sms.verify.code", msg); // 将code存入redis this.redisTemplate.opsForValue().set(KEY_PREFIX + phone, code, 5, TimeUnit.MINUTES); return true; } catch (Exception e) {
logger.error("发送短信失败。phone:{}, code:{}", phone, code); return false; }}

注意:要设置短信验证码在Redis的缓存时间为5分钟

3.注册功能:

1.校验验证码2.生成盐3.加盐加密4.新增用户5.删除Redis中的验证码hibernate-validate:对bean Validate(JSR303 规范)的实现提供了一系列的注解,通过注解就可以校验数据的合法性@Valid

4.查询用户(用户名和密码)

1.根据用户查询用户2.判断用户是否存在3.对用户输入的密码加盐加密4.对密码进行比较

转载地址:http://pxxab.baihongyu.com/

你可能感兴趣的文章
数据可视化
查看>>
Security Ressources Sites
查看>>
mysql的比较运算
查看>>
Data Breach Report
查看>>
再探偏移注射
查看>>
DNS Security Tips
查看>>
符号执行
查看>>
Remote Installation Service (RIS) in Windows Server 2003
查看>>
Layer Four Traceroute
查看>>
Hardening guide for Apache 2.2.15 on RedHat 5.4 (64bit edition)
查看>>
Microsoft Outlook Web Access (OWA) version 8.2.254.0 information disclosure vulnerability
查看>>
STP mitm attack idea
查看>>
Month of PHP Security - Summary
查看>>
近期将要购买的图书
查看>>
nginx Directory Traversal Vulnerability
查看>>
Linux下apache+svn+ssl完美结合搭建安全版本控制平台
查看>>
Nginx 0.8.35 Space Character Remote Source Disclosure
查看>>
showrun的cissp经验谈
查看>>
6月4日要买的书
查看>>
nginx Remote Source Code Disclosure and Denial of Service Vulnerabilities
查看>>