谷粒商城—商城业务—认证服务—登陆(211~224)"/>
谷粒商城—商城业务—认证服务—登陆(211~224)
一.用户注册:
0.用户 注册 流程:
1)发送验证码:接收 手机号 -> 查看redis中有没有->不存在 -> 随机生成验证码 -> 存入 redis (60s)-> 调发短信接口。
-> 存在,不能重复发送
1)验证:Valied校验 -> 手机号 去 redis 查数据 -> 如果 输入 和 redis 相同,验证通过。-> 删除 redis,调用 远程 注册接口。
-> 不同则验证失败。 phone,用户名存在,抛出异常。密码使用 MD5 消息摘要算法 加密。
1.发送短信验证码:
1)新建 gulimail-auth-server 认证的 model:
2)发送 验证码 Controller :
@RequestMapping(value = "/sendMessage11")public R message(@RequestParam(value = "phone") String phone) {R r = messageService.sendMessage(phone);return r;}
3)发送 验证码 service:
@Overridepublic R sendMessage(String phone) {//校验该手机号是否存在验证码String s = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);if (!StringUtils.isEmpty(s)) {return R.error(BizCodeEnum.EQUALS_SMS_CODE_EXCEPTION.getCode(), BizCodeEnum.EQUALS_SMS_CODE_EXCEPTION.getMsg());}String code = UUID.randomUUID().toString().substring(0, 5);//把 code 存进 redisstringRedisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, code, 1, TimeUnit.MINUTES);//opfein 调用 第三方服务 model,下,发送验证码接口R r = thirdFeign.message(phone, code);return r.put("code", code);}
2.验证 短信 验证码:
1)新建 接收 验证码 vo 类 :
/*** @Author zhangsan* @Date 2021/4/11 11:52 上午* @Version 1.0*/
@ToString
@Data
public class UserRegisVo {@NotEmpty(message = "用户名必须提交")@Length(min = 6, max = 20, message = "用户名长度为 6~20")private String name;@NotEmpty(message = "密码必须提交")@Length(min = 6, max = 20, message = "密码长度必须为 6~20")private String password;@NotEmpty(message = "手机号不能为空")@Pattern(regexp = "^((13[0-9])|(17[0-1,6-8])|(15[^4,\\\\D])|(18[0-9]))\\d{8}$", message = "手机号 格式不正确")private String phone;@NotEmpty(message = "验证码不能为空")private String code;}
2)Auth_controller :
@RequestMapping(value = "/validMessageCode")public R validMessageCode(@Valid @RequestBody UserRegisVo userRegisVo, BindingResult result) {if (result.hasErrors()) {log.info("参数匹配错误!");Map<String, String> collectMap = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));return R.error(collectMap.toString());}R r = messageService.validMessageCode(userRegisVo.getPhone(), userRegisVo.getCode());return r;}
3)Service :
@Overridepublic R validMessageCode(UserRegisVo userRegisVo) {//从 redis 取出数据String s = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisVo.getPhone());if (!StringUtils.isEmpty(s)) {if (userRegisVo.getCode().equals(s)) {//验证 成功 ,删除 验证码Boolean delete = stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegisVo.getPhone());//调用 远程会员服务 真正的 用户 注册 服务。R r = memberFeign.memberRegis(userRegisVo);if (r.getCode == 0) {//注册会员成功return R.ok().put("data", "注册会员成功");} else {//code 为 其他,则注册会员失败。return R.error().put("data", "注册会员成功");}} else {return R.error("验证失败").put("data", "验证码错误");}} else {return R.error("验证失败").put("data", "验证码错误");}}
4)远程 服务 Service:(密码加密,验证用户是否存在,)
@Overridepublic R memberRegis(MenberRegisVo menberRegisVo) {MemberDao memberDao = this.baseMapper;MemberEntity memberEntity = new MemberEntity();//设置 默认等级MemberLevelEntity memberLevelEntity = memberLevelDao.getDefaultLevel();memberEntity.setLevelId(memberLevelEntity.getId());memberEntity.setUsername(menberRegisVo.getName());// md5 (消息加密算法)密码 加密 存储BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();String encode = bCryptPasswordEncoder.encode(menberRegisVo.getPassword());memberEntity.setPassword(encode);memberEntity.setMobile(menberRegisVo.getPhone());memberEntity.setStatus(1);memberEntity.setCreateTime(new Date());//校验 用户名 是否存在,存在直接 抛出异常,让 controller 感知memberService.checkMemberUserNameUnique(memberEntity.getUsername());//校验 手机号 是否存在,存在直接 抛出异常,让 controller 感知memberService.checkMemberPhoneUnique(memberEntity.getMobile());int insert = memberDao.insert(memberEntity);return R.ok().put("insert", insert);}
3.异常机制:
1)新建异常类:PhoneExistException,UserNameExistException:
/*** @Author zhangsan* @Date 2021/4/12 11:48 上午* @Version 1.0*/
public class PhoneExistException extends RuntimeException {public PhoneExistException() {super("手机号 已经存在 异常");}
}
2)抛出异常:(验证用户/手机号 存在,立刻抛出异常)
@Overridepublic void checkMemberPhoneUnique(String phone) {MemberDao memberDao = this.baseMapper;Integer mobile = memberDao.selectCount(new QueryWrapper<MemberEntity>().eq("mobile", phone));if (mobile > 0) {throw new PhoneExistException();}}
3.MD5 / MD5 盐值加密:
1)MD5:(Message Digest algorihm 5)(信息 摘要算法)
a:压缩性:任何长度的数据,计算出的 md5 值,都是固定长度的。
b:容易计算:从原数据 就算出 md5 值 ,很容易。
d:抗修改性:对原数据有任何修改,md5 值都会出现很大改变。
e:强抗碰撞性:想找到 两个不同的数据,是他们具有相同的 md5 值,是非常困难的。
e:不可逆:
2)MD5 盐值加密:
a:通过 随机生成 随机数,与 md5 生成字符串 进行组合。
b:数据库 同时存储 md5 值 与 salt 值,验证 正确性时,使用 salt 进行 md5 即可。
3)MD5 盐值加密:(案例)(三种加密方式)
a:直接进行 MD5 加密:(md 5 不能直接进行 密码的加密,容易被 暴力破解)
String s = DigestUtils.md5Hex("jjj");System.out.println(s);
b:加盐 进行 加密:(注册时 和 登录时)
//注册 时:public void add(User user) {user.setCreateDate(new Date());user.setLastUpdateDate(new Date());//加盐,并将加过盐的密码 和盐重新存入数据库中String salt = UUID.randomUUID().toString().substring(0, 8);String password = Md5Crypt.apr1Crypt("123", substring);user.setPassword(password);user.setSalt(salt);userDAO.insert(user);}//登录时://根据账号密码查询public void myTest(){String password = "123456";// 先根据用户名获得这个用户信息,包括密码// 然后将用户输入的密码 重新按原来的加密方式加密 之后与 数据库中查出来的密码进行比对if(用户存在){//获取该用户的盐String salt = user.getSalt();//将用户输入的密码加上盐 转换为密文String md5Code = Md5Crypt.apr1Crypt("123", salt);//判断该密码是否与数据库中的密码一致if(user.getPassword().equals(md5Code)){message = "登录成功";}else{message = "密码不正确";}}System.out.println(message);}
c:Spirng 加盐 加密:(工具)
/*** 加密 之后:(每次不一样)* $2a$10$xmpmxRuKwBJN7dPi9/zoMuNUz7yJB7PsljC0fGNCG8Towbzc7LA/2* $2a$10$XtL.i83Ikq4XlTByzZSRweuqOYwTmLQ3bTTywLaq3grpbQqYHUGEu* $2a$10$/cM6F4Qx2lD7TvH/rI5.xOoJwubNTWXFHB26gr90uLZfVh8cqfrAO*/BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();//进行密码加密,存入数据库的密码。String encode = bCryptPasswordEncoder.encode("123456");System.out.println(encode);//输入 密码 和 数据库中 密码 比较。boolean matches = bCryptPasswordEncoder.matches("123456", "$2a$10$XtL.i83Ikq4XlTByzZSRweuqOYwTmLQ3bTTywLaq3grpbQqYHUGEu");System.out.println(matches); //true
4.请求转发,请求重定向:
1)请求转发:
@RequestMapping(value = "/forword11")public String forword11() {return "forword:/index.html";}
2):请求重定向,并携带 数据:
@RequestMapping(value = "/redirect11")public String redirect11(RedirectAttributes redirectAttributes) {//重定向 携带数据redirectAttributes.addFlashAttribute("aa", "value");return "redirect:/index.html";}
二.用户登录(账号密码,微博,微信):
1.账号/手机号 和 密码登录:
1)用户 登录 VO:(UserLoginVo)
@Data
public class UserLoginVo {private String nameOrPhone;private String password;
}
2)认证服务器 Controller:
@RequestMapping(value = "/login", method = RequestMethod.POST)public R login(@RequestBody UserLoginVo userLoginVo) {R r = loginService.login(userLoginVo);return r;}
3)认证服务器 Service:
@Autowiredprivate memberFeign memberFeign;@Overridepublic R login(UserLoginVo userLoginVo) {//调用 会员 服务 的 账号 密码登录 接口R r = memberFeign.userLogin(userLoginVo);return r;}
4)会员 服务器 Controller:
@Autowiredprivate CouponFeignService couponFeignService;@RequestMapping(value = "/userLogin", method = RequestMethod.POST)public R userLogin(@RequestBody MemberLoginVo memberLoginVo) {MemberLoginVo member = memberService.userLogin(memberLoginVo);if (member != null) {return R.ok();} else {return R.error();}}
5)会员 服务器 Service:
@Overridepublic MemberLoginVo userLogin(MemberLoginVo memberLoginVo) {String nameOrPhone = memberLoginVo.getNameOrPhone();String password = memberLoginVo.getPassword();//根据 用户名 从 数据库 查出密码
// 1 MemberEntity memberEntity = memberDao.getPasswordByUserNameOrPhone(nameOrPhone);
// String dbPassword = memberEntity.getPassword();MemberEntity memberEntity = memberDao.selectOne(new QueryWrapper<MemberEntity>().and(memberEntityQueryWrapper -> {memberEntityQueryWrapper.eq("username", nameOrPhone).or().eq("mobile", nameOrPhone);}));if (memberEntity == null) {return null;}//开始 校验String dbPassword = memberEntity.getPassword();BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();boolean matches = bCryptPasswordEncoder.matches(password, dbPassword);if (matches) {log.info("密码校验成功");return memberLoginVo;} else {log.info("密码校验成功");return null;}}
5)sql:
SELECT id,level_id,username,password,nickname,mobile,email,header,gender,birth,city,job,sign,source_type,integration,growth,status,create_timeFROM ums_memberWHERE ((username = 'zzddddd' OR mobile = 'zzddddd'));
2.OAuth 2.0
1)图示:
2)认证流程:
a:用户申请 微博登录认证,跳转到 微博登录页
b:登录之后,获得一个 Code,根据 Code 获取 Acess_Token
c:根据 Acess_Token ,获取微博 开放的内容。
d:根据 uid 查询,如果没有,则第一次登录,注册用户。如果有,则 更新字段。
e:无论 登录成功还是 注册成功,都返回 当前 用户信息。
e:图示:
3)注意:
a:使用 Code 换取 Acess_token ,只能换取一次。
b:每个用户的 Acess_token,即使多次获取,一段时间内不会变化。
更多推荐
谷粒商城—商城业务—认证服务—登陆(211~224)
发布评论