一、首先创建一个新的服务zidanmall-auth-server
端口为:20000
1、pom.xml:
<dependencies> <dependency> <groupId>com.jiguiquan.zidanmall</groupId> <artifactId>zidanmall-common</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
2、配置文件 bootstrap.yml:
server: port: 20000 spring: application: name: zidanmall-auth-server cloud: nacos: discovery: server-addr: localhost:8848 config: server-addr: localhost:8848 file-extension: yaml namespace: 5eb1b2f2-6e86-4929-bb22-86a7119c1f7d group: dev
3、增加认证服务的DNS域名解析
我们到现在已经在host文件中添加了4个本地域名解析了
192.168.174.141 zidanmall.com 192.168.174.141 search.zidanmall.com 192.168.174.141 item.zidanmall.com 192.168.174.141 auth.zidanmall.com
注意,修改host后不重启机器,刷新DNS的方式:ipconfig /flushdns
4、配置nginx上的 *.zidamll.com 代理到网关规则和静态文件 /static/ 规则 —— 以前章节已配置
5、配置gateway网关:
- id: zidanmall_auth_route uri: lb://zidanmall-auth-server predicates: - Host=auth.zidanmall.com
6、添加login.html和reg.html两个登录、注册页面
7、关闭开发期间的thymeleaf的缓存 application.yml:
spring: thymeleaf: cache: false #开发期间关闭缓存功能,否则修改文件没有效果
配置完成后登录页面如下:
切换到注册页面:
二、完成注册页面的发送验证码功能
1、首先完成前端页面的点击动态倒计时效果,主要就是js效果:
$(function () { $("#sendCode").click(function () { //倒计时 //给指定手机号发送验证码 if ($(this).hasClass("disabled")) { //在倒计时期间,不可用 //正在倒计时 } else { //发送验证码 $.get("/sms/sendcode?phone=" + $("#phoneNum").val(), function (data) { if (data.code != 0) { alert(data.msg); } }); timeoutChangeStyle(); } }); }) var num = 10; function timeoutChangeStyle() { $("#sendCode").attr("class", "disabled"); if (num == 0) { $("#sendCode").text("发送验证码") num = 10; $("#sendCode").attr("class", ""); } else { var str = num + "s后可再次发送"; $("#sendCode").text(str) setTimeout("timeoutChangeStyle()", 1000); } num--; }
2、html部分,就是个a标签:
<a id="sendCode"> 发送验证码 </a>
三、使用aliyun云市场—短信服务
1、当我们在云市场,购买了短信服务后,在商品的下方会有很详细的使用教程:
2、我们在第三方服务zidanmall-third-party中添加发送短信接口:
SMSService.java:
@ConfigurationProperties(prefix = "spring.cloud.alicloud.sms") @Data @Service public class SMSService { private String host; private String path; private String appcode; public void sendSMSCode(String phone, String code) { String method = "GET"; Map<String, String> headers = new HashMap<String, String>(); headers.put("Authorization", "APPCODE " + appcode); Map<String, String> querys = new HashMap<String, String>(); querys.put("content", "【云通知】您的验证码是"+ code +"。如非本人操作,请忽略本短信"); querys.put("mobile", phone); try { HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys); System.out.println(response.toString()); } catch (Exception e) { e.printStackTrace(); } } }
SMSController.java:
@RestController @RequestMapping("/sms") public class SMSController { @Autowired private SMSService smsService; @GetMapping("/sendCode") public R sendSmsCode(@RequestParam("phone") String phone, @RequestParam("code") String code){ smsService.sendSMSCode(phone, code); return R.ok(); } }
其中用到的HttpUtils地址,文档也有说明:
3、在 zidanmall-auth-server 服务,使用Feign进行调用:
ThirdPartyFeignService.java:
@FeignClient(value = "zidanmall-third-party") public interface ThirdPartyFeignService { @GetMapping("/sms/sendCode") R sendSmsCode(@RequestParam("phone") String phone, @RequestParam("code") String code); }
LoginController.java:
@Controller public class LoginController { @Autowired ThirdPartyFeignService thirdPartyFeignService; @Autowired StringRedisTemplate redisTemplate; @GetMapping("/sms/sendcode") @ResponseBody public R sendCode(@RequestParam("phone") String phone) { //TODO 接口防刷 String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone); if (!StringUtils.isEmpty(redisCode)) { long saveTime = Long.parseLong(redisCode.split("_")[1]); if (System.currentTimeMillis() - saveTime < 60 * 1000) { //60秒内 不能再发(防刷关键) return R.error(BizCodeEnum.SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.SMS_CODE_EXCEPTION.getMsg()); } } //验证码再次校验 redis保存 key->phone value->code sms:code:13812345678 - 4561 String code = UUID.randomUUID().toString().substring(0, 5); String redisStorage =code+"_"+System.currentTimeMillis(); //redis 缓存验证码 10分钟 防止同一phone 在60秒内再次发送 redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX+phone,redisStorage,10, TimeUnit.MINUTES); thirdPartyFeignService.sendSmsCode(phone,code); return R.ok(); } }
4、进行测试,页面点击发送验证码:
连续再发一条试试(60秒内)
说明我们的“短信防刷功能”可以工作!
四、通过配置,完成简单页面的跳转(WebMvcConfigurer.addViewControllers())
因为有些页面在跳转的过程中,不需要做任何业务操作,我们每次还得为其写一个Controller方法,只为进行跳转;
这样简单的工作我们可以直接使用配置完成:
@Configuration public class ZidanmallWebConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login.html").setViewName("index"); registry.addViewController("reg.html").setViewName("reg"); } }
五、完成