栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

day10-【认证服务】

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

day10-【认证服务】

目录

一、搭建环境

1.1、创建-微服务

1.2、配置文件

1.3、网关配置:

二、前端验证码倒计时 

学习产出:

学习目标:

学习内容:

学习时间:

学习产出:

学习目标:

学习内容:

学习时间:

学习产出:

学习目标:

学习内容:

学习时间:

学习产出:



一、搭建环境

1.1、创建-微服务

    com.firefly.fireflymall
    firefly-common
    0.0.1-SNAPSHOT
    
        
            com.baomidou
            mybatis-plus-boot-starter
        
    

提示:排除mybatis的依赖


1.2、配置文件

创建authserver命名空间

nacos.yml

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 124.223.14.248:8848
  application:
    name: firefly-authserver
server:
  port: 16000

 thymeleaf.yml

spring:  
  thymeleaf:
    cache: false
    suffix: .html
    prefix: classpath:/templates/

 logging.yml

# 日志级别
logging:
  level:
    com.firefly.fireflymall: debug

spring:
  jackson:
    date-format: yyyy-MM-dd
    time-zone: GMT+8

 thread.properties

firefly.thread.core.size= 20
firefly.thread.max.size= 200
firefly.thread.keep.alive.time= 10

 redis.yml

Spring:
  redis:
    host: 124.223.14.248
    port: 6379

 SpringCache.properties

#指定缓存类型为redis
spring.cache.type=redis
# 指定redis中的过期时间为1h
spring.cache.redis.time-to-live=1000000

配置域名映射:IP地址 auth.fire.flymall.com 


1.3、网关配置:
- id: firefly_authserver_route
  uri: lb://firefly-authserver
  predicates:
    - Host=auth.fire.flymall.com

提示:测试访问登录和注册页面

@Controller
@RequestMapping
public class LoginController {

    @GetMapping("/login.html")
    public String login() {
        return "login";
    }
    @GetMapping("/reg.html")
    public String reg() {
        return "reg";
    }
}

二、前端验证码倒计时 2.1、添加发送验证码按钮

定义id 使用 Jquery 触发点击事件 

   
    发送验证码 

 创建一个方法

$(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();
        }
    })
})
// 60秒
var num = 60;
function timeoutChangeStyle() {
    // 先添加样式,防止重复点击
    $("#sendCode").attr("class", "disabled")
    // 到达0秒后 重置时间,去除样式
    if (num == 0) {
        $("#sendCode").text("发送验证码")
        num = 60;
        // 时间到达后清除样式
        $("#sendCode").attr("class", "");
    } else {
        var str = num + "s 后再次发送"
        $("#sendCode").text(str);
        setTimeout("timeoutChangeStyle()", 1000);
    }
    num--;
}

2.2、映射请求页面
package com.firefly.common.config;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Component
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login.html").setViewName("login");
        registry.addViewController("/reg.html").setViewName("reg");
    }
}

2.3、整合短信验证码

    com.alibaba
    fastjson
    1.2.76


    com.aliyun
    aliyun-java-sdk-core
    3.2.3


    com.aliyun
    aliyun-java-sdk-dysmsapi
    1.0.0

SmsUtils

package com.firefly.fireflymall.fireflymallthirdparty.utils.sms;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import org.springframework.stereotype.Component;


@Component
public class SmsUtils {
	public static final String VALIDATE_CODE = "SMS_******";//发送短信验证码

	
	public void sendShortMessage(String templateCode, String phoneNumbers, String param) throws ClientException {
		// 设置超时时间-可自行调整
		System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
		System.setProperty("sun.net.client.defaultReadTimeout", "10000");
		// 初始化ascClient需要的几个参数
		final String product = "Dysmsapi";// 短信API产品名称(短信产品名固定,无需修改)
		final String domain = "dysmsapi.aliyuncs.com";// 短信API产品域名(接口地址固定,无需修改)
		// 替换成你的AK
		final String accessKeyId = "LTAIY8Mawj3VMseR";// 你的accessKeyId,参考本文档步骤2
		final String accessKeySecret = "2eHxOORZf4YzpQebROfOoXBFLHJCRY";// 你的accessKeySecret,参考本文档步骤2
		// 初始化ascClient,暂时不支持多region(请勿修改)
		IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
		DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
		IAcsClient acsClient = new DefaultAcsClient(profile);
		// 组装请求对象
		SendSmsRequest request = new SendSmsRequest();
		// 使用post提交
		request.setMethod(MethodType.POST);
		// 必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
		request.setPhoneNumbers(phoneNumbers);
		// 必填:短信签名-可在短信控制台中找到
		request.setSignName("项目名称");
		// 必填:短信模板-可在短信控制台中找到
		request.setTemplateCode(templateCode);
		// 可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
		// 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含rn的情况在JSON中需要表示成\r\n,否则会导致JSON在服务端解析失败
		request.setTemplateParam("{"code":"" + param + ""}");
		// 可选-上行短信扩展码(扩展码字段控制在7位或以下,无特殊需求用户请忽略此字段)
		// request.setSmsUpExtendCode("90997");
		// 可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
		// request.setOutId("yourOutId");
		// 请求失败这里会抛ClientException异常
		SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
		if (sendSmsResponse.getCode() != null && sendSmsResponse.getCode().equals("OK")) {
			// 请求成功
			System.out.println("请求成功");
		}
	}

	//测试-截取手机号后四位

	
	public String sendCode(String phoneNumbers, String start, String end) {
		int startInt = Integer.parseInt(start);
		int endInt = Integer.parseInt(end);

		String substring = phoneNumbers.substring(startInt, endInt);
		return substring;
	}
}

 SmsController

package com.firefly.fireflymall.fireflymallthirdparty.controller;



import com.firefly.common.utils.R;
import com.firefly.fireflymall.fireflymallthirdparty.utils.sms.SmsUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import static com.firefly.common.exception.BizCodeEnum.SEND_CODE_FAIL;
import static com.firefly.common.exception.BizCodeEnum.SEND_CODE_SUCCESS;


@Controller
@RequestMapping("/sms")
public class SmsController {

    
    @ResponseBody
    @GetMapping("/sendcode")
    public R sendCode(@RequestParam("phone") String phoneNumber,
                      @RequestParam("code") String code) {
        try {
            SmsUtils.sendCode(phoneNumber, code);
            return R.ok(SEND_CODE_SUCCESS.getCode(), SEND_CODE_SUCCESS.getMsg());
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(SEND_CODE_FAIL.getCode(), SEND_CODE_FAIL.getMsg());
        }
    }
}

远程调用短信接口:SmsFeignService 

package com.firefly.fireflymall.authserver.feign;

import com.firefly.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;


@FeignClient("firefly-third-party")
public interface SmsFeignService {
    
    @GetMapping("/sms/sendcode")
    public R sendCode(@RequestParam("phone") String phoneNumber,
                      @RequestParam("code") String code);
}
2.4、验证码防刷校验

用户要是一直提交验证码

前台:限制一分钟后提交后台:存入redis 如果有就返回

package com.firefly.fireflymall.authserver.controller;

import com.firefly.common.utils.R;
import com.firefly.fireflymall.authserver.service.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import static com.firefly.common.exception.BizCodeEnum.SMS_CODE_EXCEPTION;


@Slf4j
@Controller
public class LoginController {

    @Autowired
    private SmsService smsService;

    
    @GetMapping("/sendcode")
    public R sendCode(@RequestParam("phone") String phoneNumber) {
        try {
            smsService.sendCode(phoneNumber);
            return R.ok(SEND_CODE_SUCCESS.getCode(), SEND_CODE_SUCCESS.getMsg());
        } catch (RRException e) {
            return R.error(e.getCode(), e.getMsg());
        }
    }
}

SmsServiceImpl

package com.firefly.fireflymall.authserver.service.impl;

import com.firefly.common.exception.RRException;
import com.firefly.common.utils.RandomUtil;
import com.firefly.fireflymall.authserver.feign.SmsFeignService;
import com.firefly.fireflymall.authserver.service.SmsService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

import static com.firefly.common.constant.AuthServerConstant.SMS_CODE_REDIS_PREFIX;
import static com.firefly.common.exception.BizCodeEnum.SMS_CODE_EXCEPTION;


@Service("SmsService")
public class SmsServiceImpl implements SmsService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private SmsFeignService smsFeignService;

    @Override
    public void sendCode(String phoneNumber) {
        if (StringUtils.isNotEmpty(phoneNumber)) {
            //缓存中的key
            String redisKey = SMS_CODE_REDIS_PREFIX + phoneNumber;
            String redisCode = redisTemplate.opsForValue().get(redisKey);
            if (!StringUtils.isEmpty(redisCode)) {
                long time = Long.parseLong(redisCode.split("_")[1]);
                //防止多次刷新
                if (System.currentTimeMillis() - time < 600000) {
                    throw new RRException(SMS_CODE_EXCEPTION.getMsg(),SMS_CODE_EXCEPTION.getCode());
                }
            }else {
                String code = RandomUtil.getFourBitRandom().toUpperCase();
                // 拼接验证码
                String substring = code + "_" + System.currentTimeMillis();
                //redis缓存验证码 防止同一个phone在60秒内发出多次验证吗
                redisTemplate.opsForValue().set(redisKey, substring, 10, TimeUnit.MINUTES);
               // 调用第三方服务发送验证码
                R r = smsFeignService.sendCode(phoneNumber, code);
                if (r.getCode() != SEND_CODE_SUCCESS.getCode()) {
                    log.error(SEND_CODE_FAIL.getMsg());
                }
            }
        }
    }
}

2.5、会员注册 2.5.1、编写 vo 接收页面提交

使用到了 JSR303校验

package com.firefly.fireflymall.authserver.vo;

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;


@Data
public class UserRegistVo {
    @NotEmpty(message = "用户名必须提交")
    @Length(min = 6,max = 18,message = "用户名必须是6-18位字符")
    private String userName;

    @NotEmpty(message = "密码必须填写")
    @Length(min = 6,max = 18,message = "密码必须是6-18位字符")
    private String password;

    @NotEmpty(message = "手机号码必须提交")
    @Pattern(regexp = "^[1]([3-9])[0-9]{9}$",message = "手机格式不正确")
    private String phone;

    @NotEmpty(message = "验证码必须填写")
    private String code;
}

重定向携带数据,利用session原理,将数据放在session中 只要跳转到下一个页面取出这个数据,session中的数据就会删除掉。

TODO:分布式下 session 的问题

RedirectAttributes redirectAttributes 重定向携带数据 redirectAttributes.addFlashAttribute("errors", errors) 只能获取一次。

 前端页面获取数据:

 

 重定向地址默认是跳转到本项目的地址,如果跳转到其他服务,则需要写全路径:

 return "redirect:http://auth.fire.flymall.com/reg.html";
2.5.2、会员注册接口

LoginController

@PostMapping("/register")
public String Register(@Valid UserRegisterVo userRegisterVo, BindingResult result, RedirectAttributes redirectAttributes) {
    String url = registService.register(userRegisterVo, result, redirectAttributes);
    return url;
}

RegisterServiceImpl

    
    @Override
    public String register(UserRegisterVo userRegisterVo, BindingResult result, RedirectAttributes redirectAttributes) {
        // 校验是否通过
        if (result.hasErrors()) {
            // 拿到错误信息转换成Map
            Map errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
            //用一次的属性
            redirectAttributes.addFlashAttribute("errors", errors);
            // 校验出错,转发到注册页
            return "redirect:http://auth.fire.flymall.com/reg.html";
        }
        // 将传递过来的验证码 与 存redis中的验证码进行比较
        String code = userRegisterVo.getCode();
        String s = redisTemplate.opsForValue().get(SMS_CODE_REDIS_PREFIX + userRegisterVo.getPhone());
        //判断缓存中是否有手机号对应的验证码
        if (!StringUtils.isEmpty(s)) {
            // 判断验证码和redis中的一致
            if (code.equals(s.split("_")[0])) {
                // 删除验证码:令牌机制
                redisTemplate.delete(SMS_CODE_REDIS_PREFIX + userRegisterVo.getPhone());
                // 调用远程服务,真正注册
                R r = memberFeignService.register(userRegisterVo);
                if (r.getCode() == MEMBER_REGISTER_SUCCESS.getCode()) {
                    // 远程调用注册服务成功
                    return "redirect:http://auth.fire.flymall.com/login.html";
                } else {
                    Map errors = new HashMap<>();
                    errors.put("msg", r.getData(new TypeReference() {
                    }));
                    redirectAttributes.addFlashAttribute("errors", errors);
                    return "redirect:http://auth.fire.flymall.com/reg.html";
                }
            } else {
                Map errors = new HashMap<>();
                errors.put("code", "验证码错误");
                redirectAttributes.addFlashAttribute("code", "验证码错误");
                // 校验出错,转发到注册页
                return "redirect:http://auth.fire.flymall.com/reg.html";
            }
        } else {
            Map errors = new HashMap<>();
            errors.put("code", "验证码错误");
            redirectAttributes.addFlashAttribute("code", "验证码错误");
            // 校验出错,转发到注册页
            return "redirect:http://auth.fire.flymall.com/reg.html";
        }
    }

前端获取数据方式 

  真正完成会员注册远程接口:MemberFeignService 

package com.firefly.fireflymall.authserver.feign;

import com.firefly.common.utils.R;
import com.firefly.fireflymall.authserver.vo.MemberRegisterVo;
import com.firefly.fireflymall.authserver.vo.UserRegisterVo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;


@FeignClient("firefly-member")
public interface MemberFeignService {
    @PostMapping("/register")
    public R register(@RequestBody UserRegisterVo userRegisterVo);
}

真正的完成会员注册接口

注册信息: MemberRegister 

package com.firefly.fireflymall.member.vo;

import lombok.Data;


@Data
public class MemberRegister {
    private String userName;
    private String password;
    private String phone;
}

MemberController

微服务之间传递对象都是http+json形式

@PostMapping("/register")
public R register(@RequestBody MemberRegisterVo registerVo) {
    try {
        memberService.register(registerVo);
        return R.ok(MEMBER_REGISTER_SUCCESS.getCode(), MEMBER_REGISTER_SUCCESS.getMsg());
    } catch (RRException e) {
        return R.error(e.getCode(), e.getMsg());
    }
}
    
    @Override
    public void register(MemberRegisterVo registerVo) {
        MemberEntity memberEntity = new MemberEntity();
        // 设置默认等级
        MemberLevelEntity memberLevelEntity = memberLevelDao.getDefaultLevel();
        memberEntity.setLevelId(memberLevelEntity.getId());

        // 检查手机号和用户名是否唯一
        this.checkPhoneUnique(registerVo.getPhone());
        this.checkUserNameUnique(registerVo.getUserName());

        memberEntity.setMobile(registerVo.getPhone());
        memberEntity.setUsername(registerVo.getUserName());

        baseMapper.insert(memberEntity);
    }

    @Override
    //检查用户名是否唯一
    public void checkUserNameUnique(String username) {
        MemberDao memberDao = this.baseMapper;
        Integer count = memberDao.selectCount(new QueryWrapper().eq("username", username));
        if (count > 0) {
            throw new RRException(BizCodeEnum.USERNAME_IS_EXIST.getMsg());
        }
    }

    @Override
    //检查手机号是否唯一
    public void checkPhoneUnique(String phone) {
        MemberDao memberDao = this.baseMapper;
        Integer mobile = memberDao.selectCount(new QueryWrapper().eq("mobile", phone));
        if (mobile > 0) {
            throw new RRException(BizCodeEnum.PHONE_IS_EXIST.getMsg());
        }
    }

MD5加密

//设置密码并进行MD5加密
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encode = passwordEncoder.encode(registVo.getPassword());
entity.setPassword(encode);

学习目标:

使用到了 JSR303校验

学习与思考:密码是直接存入数据库吗?

这样子会导致数据的不安全引出了使用 MD5进行加密,但是MD5加密后,别人任然可以暴力破解可以使用加盐的方式,将密码加密后,得到一串随机字符,随机字符和密码和进行验证相同结果返回true否则false


学习时间:

提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点


学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个

学习目标:

提示:这里可以添加学习目标
例如:一周掌握 Java 入门知识


学习内容:

提示:这里可以添加要学的内容
例如:
1、 搭建 Java 开发环境
2、 掌握 Java 基本语法
3、 掌握条件语句
4、 掌握循环语句


学习时间:

提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点


学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个

学习目标:

提示:这里可以添加学习目标
例如:一周掌握 Java 入门知识


学习内容:

提示:这里可以添加要学的内容
例如:
1、 搭建 Java 开发环境
2、 掌握 Java 基本语法
3、 掌握条件语句
4、 掌握循环语句


学习时间:

提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点


学习产出:

提示:这里统计学习计划的总量
例如:
1、 技术笔记 2 遍
2、CSDN 技术博客 3 篇
3、 学习的 vlog 视频 1 个

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/736070.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号