注册

image.png

注册流程

登录注册详解 - 图2

关键技术

1、查询该用户是否存在

通过userName去数据库中查询用户是否已存在

  1. //1.检查数据库中是否已经存在该用户
  2. User dbuser = userMapper.selectByUserName(req.getUsername());
  3. if (dbuser != null) {
  4. throw new CaseServerException("用户名已存在", StatusCode.INTERNAL_ERROR);
  5. }

CaseServerException是自定义的一个异常类,它用来封装程序内部可判断出来的 Exception。
StatusCode是一个枚举类,其中INTERNAL_ERROR是自定义的一个状态码

  1. INTERNAL_ERROR(10400, "内部参数校验或逻辑出错"),

2、密码加密

加密分为多个步骤,首先生成盐,盐其实是一个 UUID:

  1. String salt = CodecUtils.generateSalt();
  2. //CodecUtils的generateSalt()方法,
  3. public static String generateSalt(){
  4. return StringUtils.replace(UUID.randomUUID().toString(), "-", "");
  5. }

generateSalt 方法:UUID.randomUUID是用来生成一个唯一的 UUID,但 UUID 的标准格式为:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12)。因此需要用StringUtils.replace方法来将“-”替换成“”,使 UUID 中的 - 去掉
其次对用户密码进行一次 MD5 加密,接着将盐(UUID)拼接上加密后的密码。最后对拼接后的字符串再进行一次 MD5 加密

  1. public static String md5Hex(String data,String salt) {
  2. if (StringUtils.isBlank(salt)) {
  3. salt = data.hashCode() + "";
  4. }
  5. return DigestUtils.md5Hex(salt + DigestUtils.md5Hex(data));
  6. }

MD5 和 md5Hex 的区别:

  • MD5 是单向加密,不可逆、不能解密的,而 md5Hex 是可逆的,可以加密也可以解密
  • MD5 是16位以 16 个元素的形式返回值,而 md5hex 是以32位16进制的小写字符串形式返回值

    3、保存

    在对密码进行加密后,将用户名、密码、盐等信息保存到数据库,并设置初始化的权限等。保存盐是为了登录时做校验的工作。

    4、set cookie

    用户注册后需要自动登录,并将登录状态保存。设置 Cookie 的值,并使其在指定时间内生效

    1. CookieUtils.setCookie(request, response, "username", req.getUsername(),
    2. 60 * 60 * 24, null, false);
  • "username":cookieName

  • req.getUsername():cookieValue
  • 60 * 60 * 24:cookieMaxAge // cookie 生效的最大秒数
  • null:encodeString
  • false:httpOnly // 是否开启 httpOnly

    登录

    登录流程

    登录注册详解 - 图3

    关键技术

    1、校验密码是否正确

    密码校验的过程和注册有点类似:

  • 先从数据库中获取用户的盐A密码B(加密后的)

  • 然后对用户输入的密码进行一次 MD5 加密,加密后得到 C
  • 随后拼接 A+C,再对 A + C 做一次 MD5 加密,得到 D
  • 最后校验 B 是否等于 D

    1. if (!dbuser.getPassword().equals(CodecUtils.md5Hex(req.getPassword(),dbuser.getSalt()))) {
    2. throw new CaseServerException("密码错误",StatusCode.INTERNAL_ERROR);
    3. }

    2、set cookie

    用户登录后,需要将登录状态保存,这一步和注册时一样

    3、权限刷新

    首先在application.properties获取权限开关authority.flag的值,判断是否开启了权限。默认是 false 的关闭状态

    1. @Value("${authority.flag}")
    2. private Boolean authorityFlag;

    开启权限开关情况下,去获取用户的authorityName(权限名称)。但用户注册时默认保存了一个空的权限名称,假如没有被修改过,那用户就会是空权限。因此当用户权限仍是空的情况下,会给用户配置默认权限名称DEFAULT_AUTHORITY_NAME,DEFAULT_AUTHORITY_NAME = “ROLE_USER”,普通用户权限

    1. if (authorityFlag) {
    2. String authorityName = dbuser.getAuthorityName();
    3. if (StringUtils.isEmpty(authorityName)) {
    4. authorityName = SystemConstant.DEFAULT_AUTHORITY_NAME;
    5. }
    6. }

    最后在数据库中查询该权限名称对应有哪些权限,并给用户设置权限

    1. if (authorityFlag) {
    2. String authorityName = dbuser.getAuthorityName();
    3. if (StringUtils.isEmpty(authorityName)) {
    4. authorityName = SystemConstant.DEFAULT_AUTHORITY_NAME;
    5. }
    6. Authority authority = authorityMapper.selectByAuthorityName(authorityName);
    7. if (Objects.nonNull(authority)) {
    8. String[] authorityContentArray = authority.getAuthorityContent().split(SystemConstant.COMMA);
    9. roleAuthority.put(authority.getAuthorityName(), Arrays.asList(authorityContentArray));
    10. LOGGER.info("刷新权限信息,authorityName: {}", authorityName);
    11. }
    12. }

    注:这里的权限是指测试用例查看的权限
    目前系统中有3种权限名称,分别是:

  • ROLE_USER:普通用户

  • ROLE_ADMIN:管理员
  • ROLE_SA:超级管理员

    退出登录

    退出登录时,会删除 cookie 中的 username 和 jsessionid