Second kill system learning

本文详细介绍了在秒杀系统中如何通过两次MD5加密和自定义手机号校验注解来增强用户登录的安全性,包括数据库表设计、密码加密策略及参数校验流程。

一、登陆 1.1 表结构的设计

DROP TABLE IF EXISTS `miaosha_user`;
CREATE TABLE `miaosha_user` (
  `id` bigint(20) NOT NULL COMMENT '用户ID,手机号码',
  `nickname` varchar(255) NOT NULL COMMENT '用户昵称',
  `password` varchar(32) DEFAULT NULL COMMENT 'MD5(MD5(pass明文+固定salt) + salt)',
  `salt` varchar(10) DEFAULT NULL,
  `head` varchar(128) DEFAULT NULL COMMENT '头像,云存储的ID',
  `register_date` datetime DEFAULT NULL COMMENT '注册时间',
  `last_login_date` datetime DEFAULT NULL COMMENT '上蔟登录时间',
  `login_count` int(11) DEFAULT '0' COMMENT '登录次数',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
复制代码

1.2 两次md5的实现
原理: 将明文密码进行第一次md5加密(加固定盐值) 以后在网络中进行传输没,服务端拿到的是表单密码,将表单密码进行第二次加密成dbPassword,根据用户输出的userId查得user对象,进行密码匹配。 好处:1. 可以避免明文密码直接在网络中传输,减少安全风险;2. 及时用户获取db中存储得密码,也是用户密码进行二次md5加密后得结果(第一次加密固定盐值,第二次加密生成一个随即得盐值),无法直接反查彩虹表得到明文密码,进一步提高了用户登陆得安全系数。

public final static String salt = "d1o2n3g4j5u";

/**
 * 第一次MD5
 * 对用户输入的密码进行加盐值然后进行MD5加密,加密后的密码是(进行网络传输时展示的密码)
 *
 * @param inputPass
 * @return
 */
public static String inputPassToFormPass(String inputPass) {
    String data = "" + salt.charAt(0) + salt.charAt(2) + inputPass + salt.charAt(5) + salt.charAt(4);
    return md5(data);
}

/**
 * 第二次MD5
 * 表单密码转换成数据库密码,dbPass是db中存储的密码
 *
 * @param formPass
 * @param dbSalt   这个盐值是随即生成的,保存到db当中
 * @return
 */
public static String formPassToDbPass(String formPass, String dbSalt) {
    String data = dbSalt.charAt(1) + dbSalt.charAt(0) + formPass + dbSalt.charAt(4) + dbSalt.charAt(5);
    return md5(data);
}

/**
 * 输入的密码直接转换成数据库密码
 *
 * @param inputPass
 * @param dbSalt
 * @return
 */
public static String inputPassToDbPass(String inputPass, String dbSalt) {
    String formPass = inputPassToFormPass(inputPass);
    return formPassToDbPass(formPass, dbSalt);
}

/**
 * MD5
 * 对传入的字符串进行加密然后返回加密结果。
 *
 * @param data
 * @return
 */
public static String md5(String data) 

// 相关的maven依赖
<!--MD5加密依赖-->
<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.6</version>
</dependency>
复制代码

1.3 用户登陆参数校验
(1)构建客户端登陆请求参数对象loginDTO
(2) 给loginDTO中的相应对象加上常用的校验注解
(3) 自定义手机号校验注解并注解到loginDTO对象的mobole参数上
(4) controller层的loginDTO参数加上@Vaild注解

自定义@mobile注解进行手机号参数校验

[
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

/**
 * Created by chenxiong on 18/12/4.
 */
@Documented
@Target(value = {ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {MobileConstraintValidator.class})
public @interface IsMobile {
    boolean required() default true;

    String message() default "手机号码格式错误";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
]

[
import org.apache.commons.lang.StringUtils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ConstraintViolation;

/**
 * Created by chenxiong on 18/12/4.
 * 使用@Constraint注解需要自定义一个实现ConstraintValidator接口的校验类。
 * 注解@Constraint注解在自定义注解@a上,@a注解在类B上
 * 若类B的作为参数并被@Valid注解所注解,哪么将会调用如下的initialize()和isValid()方法进行参数校验
 */
public class MobileConstraintValidator implements ConstraintValidator<IsMobile,String> {

    private boolean required = false;

    @Override
    public void initialize(IsMobile isMobileAnnotation) {
        required = isMobileAnnotation.required();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (required == false  || StringUtils.isEmpty(value)){
            return true;
        }else {
            return ValidatorUtil.isMobile(value);
        }
    }
}
]

[
import org.apache.commons.lang.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by chenxiong on 18/12/4.
 * 校验工具类
 */
public class ValidatorUtil {

    // 1开头,接十位数字
    private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");

    /**
     * 简单校验手机号码是否合法
     *
     * @param mobileNum
     * @return
     */
    public static boolean isMobile(String mobileNum){
        if (StringUtils.isEmpty(mobileNum)){
            return false;
        }

        Matcher matcher = mobile_pattern.matcher(mobileNum);
        return matcher.matches();
    }
}

]
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值