阳光沙滩博客系统-用户登录实现

# 用户登录流程

图片描述

# 代码实现

 @Override
    public ResponseResult doLogin(String captcha,
                                  String captchaKey,
                                  SobUser sobUser,
                                  HttpServletRequest request,
                                  HttpServletResponse response) {
        String captchaValue = (String) redisUtils.get(Constants.User.KEY_CAPTCHA_CONTENT + captchaKey);
        if (!captcha.equals(captchaValue)) {
            return ResponseResult.FAILED("人类验证码不正确");
        }
        //有可能是邮箱,也有可能是用户名
        String userName = sobUser.getUserName();
        if (TextUtils.isEmpty(userName)) {
            return ResponseResult.FAILED("账号不可以为空.");
        }

        String password = sobUser.getPassword();
        if (TextUtils.isEmpty(password)) {
            return ResponseResult.FAILED("密码不可以为空.");
        }

        SobUser userFromDb = userDao.findOneByUserName(userName);
        if (userFromDb == null) {
            userFromDb = userDao.findOneByEmail(userName);
        }

        if (userFromDb == null) {
            return ResponseResult.FAILED("用户名或密码不正确");
        }
        //用户存在
        //对比密码
        boolean matches = bCryptPasswordEncoder.matches(password, userFromDb.getPassword());
        if (!matches) {
            return ResponseResult.FAILED("用户名或密码不正确");
        }
        //密码是正确
        //判断用户状态,如果是非正常的状态,则返回结果
        if (!"1".equals(userFromDb.getState())) {
            return ResponseResult.FAILED("当前账号已被禁止.");
        }
        createToken(response, userFromDb);
        return ResponseResult.SUCCESS("登录成功");
    }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

createToken的代码

创建了两个token,一个是token,一个是refreshToken

为什么要两个tokne呢?

为什么要用两个token?

假设我们只用一个token--->

生成一个token-->有效期:2小时--->每次访问就更新---> 两个小时没有访问的话,就会要重新登录

生成一个token-->有效期:30天---->每次访问都会更新--->用户一个月没有登录,没有访问,就会过期 --->如果这个token长期保存在redis里,会占用资源。这个用户一个月才访问一次,这样就浪费资源了。

生成一个token--->有效期2个小时,保存在redis里--->过期了,我们就通过refreshToken来创建新的token-->redis 里,如果你两个小时不访问,那么redis里的token会被干掉,这样就不占用redis的资源了。如果再访问,通过refreshToken来创建新的token。如果该用户一个月没有访问,要重新登录。因为refreshToken有效期为30天。

为什么不直接使用RefreshToken--->保存在Mysql里的--->Mysql的查询速度没有Redis快

 /**
     * @param response
     * @param userFromDb
     * @return token_key
     */
    private String createToken(HttpServletResponse response, SobUser userFromDb) {
        int deleteResult = refreshTokenDao.deleteAllByUserId(userFromDb.getId());
        log.info("deleteResult of refresh token .. " + deleteResult);
        //生成token
        Map<String, Object> claims = ClaimsUtils.sobUser2Claims(userFromDb);
        //token默认有效为2个小时
        String token = JwtUtil.createToken(claims);
        //返回token的md5值,token会保存到redis里
        //前端访问的时候,携带token的md5key,从redis中获取即可
        String tokenKey = DigestUtils.md5DigestAsHex(token.getBytes());
        //保存token到redis里,有效期为2个小时,key是tokenKey
        redisUtils.set(Constants.User.KEY_TOKEN + tokenKey, token, Constants.TimeValue.HOUR_2);
        //把tokenKey写到cookies里
        //这个要动态获取,可以从request里获取,
        CookieUtils.setUpCookie(response, Constants.User.COOKIE_TOKE_KEY, tokenKey);
        //生成refreshToken
        String refreshTokenValue = JwtUtil.createRefreshToken(userFromDb.getId(), Constants.TimeValue.MONTH);
        //保存到数据库里
        //refreshToken,tokenKey,用户ID,创建时间,更新时间
        RefreshToken refreshToken = new RefreshToken();
        refreshToken.setId(idWorker.nextId() + "");
        refreshToken.setRefreshToken(refreshTokenValue);
        refreshToken.setUserId(userFromDb.getId());
        refreshToken.setTokenKey(tokenKey);
        refreshToken.setCreateTime(new Date());
        refreshToken.setUpdateTime(new Date());
        refreshTokenDao.save(refreshToken);
        return tokenKey;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
上次更新: 2022/03/28, 23:04:38