java实现用户注册、用户登录、MD5盐值加密、异常处理-50

一:编写注册数据校验接口

1.新建注册实体类对象

@Data
public class UserRegistVO {
    /**
     * 用户名
     */
    @NotEmpty(message="用户名必须提交")
    @Length(min = 6,max = 18,message="用户名必须是6到18位字符")
    private String userName;
    /**
     * 密码
     */
    @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;

}

2.编写Controller方法,实现用户注册的校验功能

 /**
     * 用户注册
     * @return
     */
    @PostMapping("/regist")
    public String register(@Validated UserRegistVO vo, BindingResult result, RedirectAttributes redirectAttributes){
        if(result.hasErrors()){
            Map<String, String> errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,FieldError::getDefaultMessage));
            redirectAttributes.addFlashAttribute("errors",errors);
            //request method post not supported
            //用户注册->/regist----->转发到reg.html,路径映射默认都是get方式访问
            //校验出错转发到注册页
            return "redirect:http://127.0.0.1:20000/reg.html";
        }
        //注册成功,回到登录首页,调用远程服务进行注册
        //todo
        //本服务的话,可以不需要加ip和端口
        return "redirect:/login.html";
    }
  • @Validated可以将实体类返回的错误信息进行校验
  • BindingResult 用来接收返回的错误信息
  • 然后通过model将错误信息返回到前台
  • FieldError::getField是stream表达式,等于 fieldError->fieldError.getField
  • redirectAttributes:模拟重定向视图,并且携带参数

二:注册功能实现

1.注册之前,先校验验证码

//1.校验验证码
        String code = vo.getCode();
        String s = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
        if(!StringUtils.isEmpty(s)){
            if(code.equals(s.split("_")[0])){
                //校验完成以后删除验证码
                stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
                //验证码校验通过,真正注册
            } else {
                //验证码不存在的话,就说明过期了
                Map<String, String> errors =new HashMap<>();
                errors.put("code","验证码错误");
                redirectAttributes.addFlashAttribute("errors",errors);
                return "redirect:http://127.0.0.1:20000/reg.html";
            }
        } else {
            //验证码不存在的话,就说明过期了
            Map<String, String> errors =new HashMap<>();
            errors.put("code","验证码错误");
            redirectAttributes.addFlashAttribute("errors",errors);
            return "redirect:http://127.0.0.1:20000/reg.html";
        }

2.编写远程注册接口

1)会员服务controller编写注册功能

@Data
public class MemberRegistVO {

    /**
     * 用户名
     */
    private String userName;
    /**
     * 密码
     */
    private String password;
    /**
     * 手机号
     */
    private String phone;
}

     /**
     * 会员注册功能
     * @return
     */
    @PostMapping("/regist")
    public R regist( @RequestBody MemberRegistVO vo){
        try {
            memberService.regist(vo);
        } catch (PhoneExistException e) {
            return R.error(BizCodeEnume.PHONE_EXIST_EXCEPTION.getCode(),BizCodeEnume.PHONE_EXIST_EXCEPTION.getMsg());
        } catch (UserNameExistException e){
            return R.error(BizCodeEnume.USER_EXIST_EXCEPTION.getCode(),BizCodeEnume.USER_EXIST_EXCEPTION.getMsg());
        }
        return R.ok();
    }

2)校验用户名和手机号的唯一性

自定义异常:用户名存在异常和手机号存在异常

public class UserNameExistException extends RuntimeException {

    public UserNameExistException() {
        super("用户名存在异常");
    }
}

public class PhoneExistException extends RuntimeException{
    public PhoneExistException() {
        super("手机号存在异常");
    }
}

去数据库查询,如果已经保存用户名或者手机号,直接将异常抛出去

/**
     * 校验手机号唯一性
     * @param phone
     * @throws PhoneExistException
     */
    @Override
    public void checkPhoneUnique(String phone) throws PhoneExistException{
        MemberDao memberDao = this.baseMapper;
        QueryWrapper<MemberEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("mobile",phone);
        Integer mobileCount = memberDao.selectCount(wrapper);
        if(mobileCount>0){
            throw new PhoneExistException();
        }
    }
    /**
     * 校验用户名唯一性
     * @param username
     * @throws UserNameExistException
     */
    @Override
    public void checkUserNameUnique(String username) throws UserNameExistException{
        MemberDao memberDao = this.baseMapper;
        QueryWrapper<MemberEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        Integer userNameCount = memberDao.selectCount(wrapper);
        if(userNameCount>0){
            throw new UserNameExistException();
        }
    }
  • service的方法都是void,没有返回值,上层业务想要获取异常,就抛出去,然后再controller进行捕获

3.将密码加密存储——MD5

1) MD5-Message Digest algorithm 5,信息摘要算法

 • 压缩性:任意长度的数据,算出的MD5值长度都是固定的。 
 • 容易计算:从原数据计算出MD5值很容易。 
 • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。 
 • 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。 
 • 不可逆

2) 加盐

• 通过生成随机数与MD5生成字符串进行组合
• 数据库同时存储MD5值与salt值。验证正确性时使用salt进行MD5即可

3)代码实现

      //设置密码,MD5不能直接进行加密存储->需要盐值加密,随机值->BCryptPasswordEncoder
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encode = passwordEncoder.encode(vo.getPassword());
        entity.setPassword(encode);

注:使用BCryptPasswordEncoder就不需要在数据库维护salt盐值字段了,其可以在加密生成的代码中,融入盐值,完成校验。

4.验证码校验完成后,远程调用会员注册接口

1)新建MemberFeignService

@FeignClient("gulimail-member")
public interface MemberFeignService {
    /**
     * 会员注册功能
     * @return
     */
    @PostMapping("/member/member/regist")
    public R regist( @RequestBody UserRegistVO vo);
}

2)接口实现成功

/**
     * 用户注册
     * @return
     */
    @PostMapping("/regist")
    public String register(@Validated UserRegistVO vo, BindingResult result, RedirectAttributes redirectAttributes){
        if(result.hasErrors()){
            Map<String, String> errors = result.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField,FieldError::getDefaultMessage));
            redirectAttributes.addFlashAttribute("errors",errors);
            //request method post not supported
            //用户注册->/regist----->转发到reg.html,路径映射默认都是get方式访问
            //校验出错转发到注册页
            return "redirect:http://127.0.0.1:20000/reg.html";
        }
        //注册成功,回到登录首页,调用远程服务进行注册
        //1.校验验证码
        String code = vo.getCode();
        String s = stringRedisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
        if(!StringUtils.isEmpty(s)){
            if(code.equals(s.split("_")[0])){
                //校验完成以后删除验证码
                stringRedisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
                //验证码校验通过,真正注册
                try {
                    R r = memberFeignService.regist(vo);
                    if(r.getCode() == 0){
                        //成功
                        return "redirect:/login.html";
                    } else {
                        //失败
                        Map<String, String> errors =new HashMap<>();
                        errors.put("msg",r.getData(new TypeReference<String>(){}));
                        redirectAttributes.addFlashAttribute("errors",errors);
                        return "redirect:http://127.0.0.1:20000/reg.html";
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                //验证码不存在的话,就说明过期了
                Map<String, String> errors =new HashMap<>();
                errors.put("code","验证码错误");
                redirectAttributes.addFlashAttribute("errors",errors);
                return "redirect:http://127.0.0.1:20000/reg.html";
            }
        } else {
            //验证码不存在的话,就说明过期了
            Map<String, String> errors =new HashMap<>();
            errors.put("code","验证码错误");
            redirectAttributes.addFlashAttribute("errors",errors);
            return "redirect:http://127.0.0.1:20000/reg.html";
        }
        //todo
        //本服务的话,可以不需要加ip和端口
        return "redirect:/login.html";
    }

三:登录接口实现

1.编写UserLoginVo

@Data
public class UserLoginVO {
    private String loginAccount;
    private String password;
}

2.编写会员服务controller

 /**
     * 会员登录功能
     * @return
     */
    @PostMapping("/login")
    public R login( @RequestBody MemberLoginVO vo){
        MemberEntity entity = memberService.login(vo);
        if(entity!=null){
            return R.ok();
        } else {
            return R.error(BizCodeEnume.LOGINACCOUNT_PASSWORD_INVAILD_EXCEPTION.getCode(),BizCodeEnume.LOGINACCOUNT_PASSWORD_INVAILD_EXCEPTION.getMsg());
        }
    }

3.编写会员服务service

 @Override
    public MemberEntity login(MemberLoginVO vo) {
        String loginAccount = vo.getLoginAccount();
        String password = vo.getPassword();
        //1.去数据库查询
        MemberDao memberDao = this.baseMapper;
        QueryWrapper<MemberEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("username",loginAccount).or().eq("mobile",loginAccount);
        MemberEntity memberEntity = memberDao.selectOne(wrapper);
        if(memberEntity == null){
            //登陆失败
            return null;
        } else {
            //1.获取数据库存储的密码
            String passwordDb = memberEntity.getPassword();
            //2.和前台传过来的密码进行对比
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            boolean matches = passwordEncoder.matches(password, passwordDb);
            if(matches){
                return memberEntity;
            } else {
                return null;
            }
        }
    }

4.编写远程调用接口

@FeignClient("gulimail-member")
public interface MemberFeignService {
    /**
     * 会员注册功能
     * @return
     */
    @PostMapping("/member/member/regist")
    R regist( @RequestBody UserRegistVO vo);

    /**
     * 会员登录功能
     * @return
     */
    @PostMapping("/member/member/login")
    R login( @RequestBody UserLoginVO vo);
}

5.auth模块调用会员模块

@PostMapping("/login")
    public String login(UserLoginVO vo){
        //远程登录
        R r = memberFeignService.login(vo);
        if(r.getCode() == 0){
            //成功就去首页
            return "redirect:http://127.0.0.1:10000";
        } else {
            //失败就去登录页
            return "redirect:http://127.0.0.1:20000/login.html";
        }
    }

在这里插入图片描述
登录成功!!!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MD5加密是一种在MD5加密算法的基础上增加一个(salt)进行加密的方法,目的是增加密码的安全性。在JavaScript中,可以通过添加实现MD5加密。 在引用中提供了几种MD5加密的方法,例如: - 使用在密码前后进行拼接,然后再进行MD5加密,例如:md5($salt.$pass)、md5($pass.$salt)、md5($salt.$pass.$salt)、md5(md5($pass).$salt)、md5($salt.md5($pass))。 - 双重MD5加密也可以使用,例如:md5(md5(pwd))。 在引用的例子中,可以看到一个使用MD5加密JavaScript代码示例,其中使用了md5(values.userName + values.passWord),将用户名和密码拼接后进行MD5加密。 综上所述,MD5加密是在MD5加密算法基础上增加进行加密的方法,可以通过在密码前后添加实现。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [MD5加密](https://blog.csdn.net/T_james/article/details/79528085)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [前端md5加加密](https://blog.csdn.net/weixin_42579348/article/details/129020695)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随意石光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值