一、业务描述

以注册、登录为主线,串联起验证码生成及校验、邮件发送、IP防暴刷、用户统一认证等功能。
实现需基于Spring Cloud 微服务架构,技术涉及Nginx、Eureka、Feign(Ribbon、Hystrix)、Gateway、Config+Bus等。

1.1 注册

1)用户访问到登录页面,在登录页面中有注册新账号功能
2)点击“注册新账号“,跳转到注册页面
3)在注册页面,需要用户输入邮箱地址、密码、确认密码,然后点击”获取验证码“,系统会生成验证码并向所输入的邮箱地址发送该验证码,用户拿到邮箱中的验证码输入后完成注册

规则如下
A:一分钟内只允许获取一次验证码(前端Js控制即可),验证码为随机生成的6位数字,10分钟内有效,验证码存储到mysql数据库中(也可以选择存入到Redis中);

B:存储到mysql数据库之后,使用发邮件功能,将该验证码发送到所输入的邮箱地址中

C:用户从邮箱中拿到验证码,点击注册时,需要进行行校验,因为验证码已经存入数据库,此时只需要查询数据库中该邮箱地址对应的最近一次的验证码记录,校验验证码是否正确,是否超时,若有问题,准确提示给用户

4)注册成功后,根据 <用户邮箱+密码> 生成签发token令牌(此处生成一个UUID模拟即可),该token令牌存入数据库(也可以选择存入到Redis中),并写入cookie中(以后的每次请求都会在cookie中携带该token,网关过滤器通过验证token的合法性来确定用户请求是否合法,如果token合法,根据token取出用户信息---->邮箱),最后重定向到欢迎⻚页面(显示邮箱地址)

1.2 登录

1)用户访问登录页面,在登录页面输入邮箱地址+密码
2)点击登录,后台对用户名和密码进行验证,然后根据<用户邮箱+密码> 生成签发token令牌(此处生成一个UUID模拟即可),该token令牌存入数据库(因为大家未系统学习Redis,所以此处令牌存入数据库即可),并写入cookie中(以后的每次请求都会在cookie中携带该token,网关过滤器通过验证token的合法性来确定用户请求是否合法,如果token合法,根据token取出用户信息---->邮箱),最后重定向到欢迎页面(显示邮箱地址)

1.3 架构描述

  • Nginx
    占⽤用端⼝口:80
    实现动静分离。将静态资源 html 页面存放至本地磁盘,数据请求统一经过 GateWay 网关路由到下游微服务。

  • 静态资源(html页面)
    访问前缀:/static/xxx.html
    包括登录页面 login.html、注册页面 register.html、以及成功登录之后的欢迎页面welcome.html,各个页面细节元素后面有描述

  • GateWay 网关
    占用端口:9002端口 数据请求前缀:/api/xxx
    完成统一路由、IP防暴刷(限制单个客户端IP在最近X分钟内请求注册接口不能超过Y次)、统一认证(登录时验证用户名密码是否合法,合法调用用户微服务生成token,写入cookie,并且携带邮箱地址重定向到欢迎页面;后续请求再到来时,验证客户端请求cookie中携带的token是否合法,合法则放行,此处不考虑token更新问题)等功能

    路路径路路由规则:
    /api/user/** 路由到用户微服务
    /api/code/** 路由到验证码微服务
    /api/email/** 路由到邮件微服务

  • dabing-service-user 用户微服务
    占用端口:8080 数据请求前缀:/api/user/**
    提供注册接口、用户是否已注册接口、登录接口(⽣生成token并入库,token写入cookie中)、查
    询用户登录邮箱接口等

  • dabing-service-code 验证码微服务
    占用端口:8081 数据请求前缀:/api/code/**
    用于提供验证码生成、验证码校验等接口,同时调用邮件微服务发送验证码

  • dabing-service-email 邮件微服务
    占用端口:8082 数据请求前缀:/api/email/**
    提供邮件发送功能,用于将生成的验证码发送到注册邮箱

  • Spring Cloud Config+Bus
    占用端口: 9006
    共享的配置:数据库连接信息、邮件发送相关配置、IP防暴暴刷指标参数(X分钟的X,Y上限的Y)
    注意:除去Eureka是2个实例的集群模式,其他保持单实例

1.4 接口描述

涉及到的微服务名称定义、接口定义、参数名称,可以和下文提到的保持一致。

微服务名称 API 接口 返回值 接口描述
dabing-service-use /user/register/{email}/{password}/{code} true/false 注册接⼝口,true成功,false失败
/user/isRegistered/{email} true/false 是否已注册,根据邮箱判断,true代表已经注册过,false代表尚未注册
/user/login/{email}/{password} 邮箱地址 登录接⼝口,验证⽤用户名密码合法性,根据⽤用户名和密码⽣生成token,token存⼊入数据库,并写⼊入cookie中,登录成功返回邮箱地址,重定向到欢迎⻚页
/user/info/{token} 根据token查询⽤用户登录邮箱接⼝口
dabing-service-code /code/create/{email} true/false ⽣生成验证码并发送到对应邮箱,成功true,失败false
/code/validate/{email}/{code} 0/1/2 校验验证码是否正确,0正确1错误2超时
dabing-service-email /email/{email}/{code} true/false 发送验证码到邮箱,true成功,false失败

1.5 页面描述

涉及到界面的,界面样式不做要求,界面元素完备即可。

  • 登录界面 login.html

    登录界面包含输入项:
    邮箱:email
    密码:password
    点击“登录”调用登录接口,成功后重定向到欢迎页面welcome.html
    ajax调用http://localhost:9002/api/user/login/{email}/{password}
    点击“注册新账号”可跳转到注册页面register.html

  • 注册界面 register.html

    注册界面包含输入项:
    邮箱:email
    密码: password
    确认密码:ConfirmPassword
    验证码:code
    点击“获取验证码”:调用获取验证码接口 http://localhost:9002/code/create/{email}
    点击”注册“:调用注册接口 http://localhost:9002/user/register/{email}/{password}/{code}

  • 欢迎页面 welcome.html
    如下显示登录账户信息即可

1.6 关于网关和配置中心的说明

  • GateWay网关

    • 统一路由,数据请求的统一出入口
    • 添加全局过滤器,进行IP注册接口的防暴刷控制,超过阈值直接返回错误码及错误信息(错
      误码:303,错误信息:您频繁进行注册,请求已被拒绝)
    • 添加全局过滤,进行token的验证,用户微服务和验证码微服务的请求不过滤(网关调用下游
      用户微服务的token验证接口)
  • Config配置中心
    将数据库配置、邮件发送相关配置、防暴刷参数配置,使用Config进行管理,对应微服务可以在自己的配置文件中直接使用${xxx.yyy}的方式取出使用

1.7 关于数据表的说明

涉及到两个数据表:验证码存储表+令牌存储表,数据表参考如下

验证码存储表

-- ----------------------------
-- Table structure for dabing_auth_code
-- ----------------------------
DROP TABLE IF EXISTS `dabing_auth_code`;
CREATE TABLE `dabing_auth_code` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '⾃自增主键',
`email` varchar(64) DEFAULT NULL COMMENT '邮箱地址',
`code` varchar(6) DEFAULT NULL COMMENT '验证码',
`createtime` datetime DEFAULT NULL COMMENT '创建时间',
`expiretime` datetime DEFAULT NULL COMMENT '过期时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;

令牌存储表

-- ----------------------------
-- Table structure for dabing_token
-- ----------------------------
DROP TABLE IF EXISTS `dabing_token`;
CREATE TABLE `dabing_token` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '⾃自增主键',
`email` varchar(64) NOT NULL COMMENT '邮箱地址',
`token` varchar(255) NOT NULL COMMENT '令牌',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;

1.8 关于测试

  • 注册测试
  • 登录测试
  • 未登录状态下,清空cookie,直接访问后台的邮件服务,http://www.dabing.com/api/email/{email}/{code},验证无token情况下是否被网关拦截

1.9 关于跨域

前文在 Html 静态页面中有ajax 请求数据API统一接口9002的地方,会涉及跨域问题,可以考虑将静态
资源和数据请求接口放在同一个域名下,根据url前缀在nginx层进行区分。

比如所有部署,包括nginx都在一台机器上
可以给机器设置一个域名 www.dabing.com
静态资源访问 www.dabing.com/static/xxx.html
数据API接口请求 www.dabing.com/api/xxx/yyy
通过/static和/api在nginx层进行区分


1.10 效果视频验证:

注册新账号
一分钟内只允许获取一次验证码
发邮件功能
校验验证码
验证码超时展示
保存令牌数据库
令牌保存cookie中
跳转到欢迎页面
登录
生成Token保存到令牌表和Cookies中最后转到欢迎页面
未登录状态网关拦截
IP防暴刷过滤器:在1分钟内注册超过100次时返回错误信息

二、功能实现:

2.1 一分钟内只允许获取一次验证码

2.2 IP防暴刷过滤器
@Component
@RefreshScope // 刷新配置信息
public class IpGlobalFilter implements GlobalFilter, Ordered {@Value("${filter.limit.ip.uri}")private String limitUri;@Value("${filter.limit.ip.maxtimes}")private int maxTimes;@Value("${filter.limit.ip.limitminutes}")private int limitMinutes;private static ConcurrentMap<String, List<Long>> ipCache = new ConcurrentHashMap<>();public IpGlobalFilter() {System.out.println("IpGlobalFilter初始化");}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println(maxTimes);ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();// 客户端IPString ip = request.getRemoteAddress().getHostString();String path = request.getURI().getPath();// 如果请求的服务未设限,直接放行if (!path.startsWith(limitUri)) {return chain.filter(exchange);}// 设限服务把本次请求加入缓存List<Long> currentIpCache = ipCache.get(ip);// 初始化当前ip请求记录if (currentIpCache == null) {currentIpCache = new ArrayList<>();ipCache.put(ip, currentIpCache);}currentIpCache.add(System.currentTimeMillis());// 计算limitMinutes内访问次数是否超过maxTimesint count = 0;long startTime = System.currentTimeMillis() - (limitMinutes * 60 * 1000);for (Long reqTime : currentIpCache) {if (reqTime > startTime) {count++;}}if (count > maxTimes) {response.setStatusCode(HttpStatus.FORBIDDEN);String data = "您频繁进⾏注册,请求已被拒绝!";DataBuffer wrap = response.bufferFactory().wrap(data.getBytes());return response.writeWith(Mono.just(wrap));}return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}
2.3 未登录状态网关拦截
@Component
public class TokenGlobalFilter implements GlobalFilter, Ordered {@Autowiredprivate UserFeignClient userFeignClient;/*** 进⾏token的验证,⽤户微服务和验证码微服务的请求不过滤(⽹关调⽤下游⽤户微服务的token验证接⼝)* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String path = request.getURI().getPath();// 用户微服务和验证码微服务的请求不过滤if (path.startsWith("/api/user") || path.startsWith("/api/code")) {return chain.filter(exchange);}// 获取Cookie,token不存在或者用户微服务查询不到重定向到登录页面List<HttpCookie> cookies = request.getCookies().get("token");if (!CollectionUtils.isEmpty(cookies)) {HttpCookie cookie = cookies.get(0);String token = cookie.getValue();if (!"".equals(userFeignClient.info(token))) {return chain.filter(exchange);}}// 返回状态码 303,重定向到登录页面response.getHeaders().set(HttpHeaders.LOCATION, "/static/login.html");response.setStatusCode(HttpStatus.SEE_OTHER);return response.setComplete();}@Overridepublic int getOrder() {return 0;}
}
2.4 网关配置
server:port: 9090
eureka:client:serviceUrl:defaultZone: http://dabingcloudeurekaservera:8761/eureka/,http://dabingcloudeurekaserverb:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表instance:prefer-ip-address: trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
spring:application:name: dabing-cloud-gatewaycloud:gateway:routes:- id: service-code-routeruri: lb://dabing-service-codepredicates:- Path=/api/code/**filters:- StripPrefix=1- id: service-user-routeruri: lb://dabing-service-userpredicates:- Path=/api/user/**filters:- StripPrefix=1httpclient:connect-timeout: 5000response-timeout: 20000
2.5 nginx配置
worker_processes  1;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;keepalive_timeout  65;upstream myServer {server 127.0.0.1:9090;}server {listen       80;server_name  localhost;location /static/ {root staticDatas;}location / {root   html;index  index.html index.htm;}location /api {proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_pass http://myServer;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}}
}
2.6 静态资源路径

注意:请求静态资源的时候,url地址栏需要使用配置的本地域名进行访问,否则报跨域问题

补充:不使用域名实现 跨域

1. 效果

2. 实现,在网关配置全局跨域

server:port: 9090
eureka:client:serviceUrl:defaultZone: http://dabingcloudeurekaservera:8761/eureka/,http://dabingcloudeurekaserverb:8762/eureka/ #把 eureka 集群中的所有 url 都填写了进来,也可以只写一台,因为各个 eureka server 可以同步注册表instance:prefer-ip-address: trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
spring:application:name: dabing-cloud-gatewaycloud:gateway:#开启网关的跨域功能,具体微服务上的跨域需要进行关闭,否则无效globalcors:cors-configurations:'[/**]': # 匹配所有请求allowedOrigins: "*"   #跨域处理 允许所有的域allowedMethods:     # 支持的方法- GET- POST- PUT- DELETEroutes:- id: service-code-routeruri: lb://dabing-service-codepredicates:- Path=/api/code/**filters:- StripPrefix=1- id: service-user-routeruri: lb://dabing-service-userpredicates:- Path=/api/user/**filters:- StripPrefix=1httpclient:connect-timeout: 5000response-timeout: 20000

仓库地址:

demo仓库地址:https://gitee.com/lg_zk/dabing-user-parent-hw.git

springcloud注册demo(使⽤第⼀代Spring Cloud核⼼组件完成项⽬构建、编码及测试)相关推荐

  1. SpringCloud学习笔记(1)- Spring Cloud Alibaba

    文章目录 SpringCloud学习笔记(1)- Spring Cloud Alibaba 服务治理 Nacos 服务注册 Nacos 服务发现与调用 Ribbon 负载均衡 Sentinel 服务限 ...

  2. SpringCloud学习笔记3:Spring Cloud Netflix 组件(五大神兽)

    一.Spring Cloud Netflix有哪些组件? eureka (提供服务注册与发现功能) ribbon(提供负载均衡功能) Feign(整合了ribbon和Hystrix,具有负载均衡和熔断 ...

  3. (十六)java springcloud版b2b2c社交电商spring cloud分布式微服务-使用spring cloud Bus刷新配置...

    b2b2c电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.我们使用spring cloud分布式微服务云架构做了b2b2c的电子商务系统,除了架构本身自带的系统服务外,我们将b2b2c的业务服 ...

  4. SpringCloud学习笔记(1)- Spring Cloud Netflix

    文章目录 SpringCloud学习笔记(1)- Spring Cloud Netflix 单体应用存在的问题 Spring Cloud Eureka Eureka Server代码实现 Eureka ...

  5. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负载均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  6. eureka集群只注册一个_一、Spring Cloud Eureka服务注册中心

    Sping boot Eureka是服务中心,管理各种服务功能包括服务的注册.发现.熔断.负载.降级等.Spring Cloud Eureka 是对Netflix公司的Eureka的二次封装. 在du ...

  7. Spring Cloud 各组件调优参数

    Spring Cloud整合了各种组件,每个组件往往还有各种参数.本文来详细探讨Spring Cloud各组件的调优参数. Tomcat配置参数 1 server: 2 tomcat: 3 max-c ...

  8. Spring Cloud各组件

    讲的不错:http://www.ityouknow.com/springcloud/2017/05/16/springcloud-hystrix.html Spring Cloud技术应用从场景上可以 ...

  9. spring cloud各组件详解

    一,Eureka 服务注册中心,特性有失效剔除.服务保护.健康检查. 二.Ribbon 客户端负载均衡,特性有区域亲和.重试机制. 三.Hystrix 客户端容错保护,特性有服务降级.服务熔断.请求缓 ...

最新文章

  1. 如何写好一篇高质量的IEEE/ACM Transaction级别的计算机科学论文?
  2. tilemap 导入unity_教程|Unity中使用Tilemap快速创建2D游戏世界
  3. 在MFC中创建动态控件的生成与响应
  4. U3D中物体的渲染顺序
  5. 《财富》:盖茨的四项黄金法则
  6. mysql不能删除外键吗,MySQL不能删除外键约束所需的索引
  7. 平衡二叉树的自顶向下递归和自底向上递归
  8. c语言子线程给主线程发信息,如何用C语言实现多线程
  9. 心得 | 《用得上的商学课》 004 边际成本 | 飞机起飞前的座位,只卖一块钱?...
  10. html5中切换图片怎么做,HTML5编程实战之二:用动画的形式切换图片
  11. 传感器网络与物联网-1.射频识别技术
  12. 力扣-700 二叉搜索树中的搜索
  13. recordset.Open strSql, Conn, 3,3
  14. (原创)Lottie动画使用介绍
  15. 虚拟化部署ESXI6.7+intel x710-da4万兆网卡
  16. iPhoneXSM屏幕适配、 各机型的逻辑分辨率
  17. Koo叔说Shader-贴图切换
  18. python到底有多少个库_11个你可能不知道的Python库
  19. Markdown 字体颜色汇总表(简洁版)- 适用于所有需要颜色任务
  20. 推荐5款轻量级的小软件,界面简洁无广告

热门文章

  1. Linux Shell文本处理工具集锦
  2. POJ 1183 反正切函数的应用(数学代换,基本不等式)
  3. Java-idea-生成for循环
  4. 57、Design Support Library 介绍及环境搭建
  5. 冲刺!11.14-11.15
  6. jar包中的类如何读取包内和包外的配置文件
  7. 第七章—JavaScript数组
  8. Timer lock
  9. 【转】Android应用的自动升级、更新模块的实现 (2)
  10. QTP工作原理的学习心得